2

I have a module, that contains a bunch of functions that generate xml's

In other module I am constructing a class, and I want to assign one of those function to a class variable

Problem is, the fuction acts as a class method and when i call it from another class method, it passes self as a first argument.

Did i choose a good design approach? How to avoid passing self to a function? (@staticmethod decorator before generate = gen.generate doesn't work)

I would like to avoid making a class out of generate function if possible

Thanks!

generators.py

def generate(id, date):
 pass
def generate_another():
 pass

main.py

import generators as gen
class Client():
 generate = gen.generate
 def get_result(self, *args, **qwargs):
 request = self.generate(id, date)
asked Mar 3, 2020 at 0:05
6
  • 1
    Why do you even need to self.generate? Why not just call it directly as gen.generate(). Why should it be a static method instead of a function? This smells strongly of xyproblem.info Commented Mar 3, 2020 at 0:09
  • @jordanm - a subclass can define a different generate or even an object method generate that uses state on the object and get_result would still work. Not saying that's the intent here, but its a reasonable pattern. Commented Mar 3, 2020 at 0:26
  • @tdelaney personally, if that's the case, I would prefer to provide that externally as an argument, so client = Client(gen.generate). Then there's not even a need for the staticmethod decorator Commented Mar 3, 2020 at 0:31
  • @juanpa.arrivillaga - yes, that is a good way to go. But I've written factory functions that do something kind-of like this using external configuration. In my case, it was a test suite and the goal was to keep the test cases as generic as possible. Commented Mar 3, 2020 at 0:47
  • @tdelaney yeah, my intent was for subclassing, creating different clients with different generators (and other behaviour) and sharing get_result method. How did you archeve it? Similar to juanpa.arrivillaga's answer? Commented Mar 3, 2020 at 11:38

2 Answers 2

2

You must understand, that:

@decorator
def some_func():
 pass

Is just syntactic sugar for

def some_func():
 pass
some_func = decorator(some_func)

So in this case, you just want:

import generators as gen
class Client:
 generate = staticmethod(gen.generate)
 def get_result(self, *args, **qwargs):
 request = self.generate(id, date)

As to whether or not this is a good design decision, it's probably too much of an opion-based question. Personally, I tend to avoid staticmethod. What advantage does this design offer over simply calling gen.generate inside get_result?

answered Mar 3, 2020 at 0:21

1 Comment

The intent was creating a bunch of clients with different generators. So to every subclass i wanted to assign it's own generator function in a uniform way. Thanks for the answer!
0

This is nearly a duplicate of @juanpa.arrivillaga's answer, but with a simplification which highlights a potential design advantage, addressing Juanpa's question in the case where we're truly using a static method (no self arg needed).

Code which originally looks like this (class with a decorated static method)...

import generators as gen
class Client:
 @staticmethod
 def get_result(*args, **qwargs):
 request = gen.generate(id, date)

... could be simplified as:

import generators as gen
class Client:
 get_result = staticmethod(gen.generate)

In Juanpa's answer, the class has two ways of calling the same underlying gen.generate:

client = Client()
# 1. as a class method
client.get_result()
# 2. as a static method
client.generate()

This all neglects the details of what is done with the request object etc, but if the same external function can be recycled completely as a staticmethod in multiple classes, Juanpa's answer helps keep static methods DRY:

def recycled_function(some_arg):
 ...
class ClassOne:
 static_func = staticfunction(recycled_function)
class ClassTwo:
 static_func = staticfunction(recycled_function)

This approach is more concise than copying the full implementation of recycled_function into each class decorated by @staticmethod, or even by making a wrapper method or static function to call the external recycled_function.

answered Feb 16, 2023 at 17:52

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.