When I attempt to use a static method from within the body of the class, and define the static method using the built-in staticmethod function as a decorator, like this:
class Klass(object): @staticmethod # use as decorator def _stat_func(): return 42 _ANS = _stat_func() # call the staticmethod def method(self): ret = Klass._stat_func() + Klass._ANS return retI get the following error:
Traceback (most recent call last): File "call_staticmethod.py", line 1, in <module> class Klass(object): File "call_staticmethod.py", line 7, in Klass _ANS = _stat_func() TypeError: 'staticmethod' object is not callableI understand why this is happening (descriptor binding), and can work around it by manually converting _stat_func() into a staticmethod after its last use, like so:
class Klass(object): def _stat_func(): return 42 _ANS = _stat_func() # use the non-staticmethod version _stat_func = staticmethod(_stat_func) # convert function to a static method def method(self): ret = Klass._stat_func() + Klass._ANS return retSo my question is:
Are there cleaner or more "Pythonic" ways to accomplish this?
26 Answers
staticmethod objects apparently have a __func__ attribute storing the original raw function (makes sense that they had to). So this will work:
class Klass(object): @staticmethod # use as decorator def stat_func(): return 42 _ANS = stat_func.__func__() # call the staticmethod def method(self): ret = Klass.stat_func() return retAs an aside, though I suspected that a staticmethod object had some sort of attribute storing the original function, I had no idea of the specifics. In the spirit of teaching someone to fish rather than giving them a fish, this is what I did to investigate and find that out (a C&P from my Python session):
>>> class Foo(object):
... @staticmethod
... def foo():
... return 3
... global z
... z = foo
>>> z
<staticmethod object at 0x0000000002E40558>
>>> Foo.foo
<function foo at 0x0000000002E3CBA8>
>>> dir(z)
['__class__', '__delattr__', '__doc__', '__format__', '__func__', '__get__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
>>> z.__func__
<function foo at 0x0000000002E3CBA8>Similar sorts of digging in an interactive session (dir is very helpful) can often solve these sorts of question very quickly.
This is the way I prefer:
class Klass(object): @staticmethod def stat_func(): return 42 _ANS = stat_func.__func__() def method(self): return self.__class__.stat_func() + self.__class__._ANSI prefer this solution to Klass.stat_func, because of the DRY principle.
Reminds me of the reason why there is a new super() in Python 3 :)
But I agree with the others, usually the best choice is to define a module level function.
For instance with @staticmethod function, the recursion might not look very good (You would need to break DRY principle by calling Klass.stat_func inside Klass.stat_func). That's because you don't have reference to self inside static method.
With module level function, everything will look OK.
What about injecting the class attribute after the class definition?
class Klass(object): @staticmethod # use as decorator def stat_func(): return 42 def method(self): ret = Klass.stat_func() return ret
Klass._ANS = Klass.stat_func() # inject the class attribute with static method value 2 This is due to staticmethod being a descriptor and requires a class-level attribute fetch to exercise the descriptor protocol and get the true callable.
From the source code:
It can be called either on the class (e.g.
C.f()) or on an instance (e.g.C().f()); the instance is ignored except for its class.
But not directly from inside the class while it is being defined.
But as one commenter mentioned, this is not really a "Pythonic" design at all. Just use a module level function instead.
8What about this solution? It does not rely on knowledge of @staticmethod decorator implementation. Inner class StaticMethod plays as a container of static initialization functions.
class Klass(object): class StaticMethod: @staticmethod # use as decorator def _stat_func(): return 42 _ANS = StaticMethod._stat_func() # call the staticmethod def method(self): ret = self.StaticMethod._stat_func() + Klass._ANS return ret 3 If the "core problem" is assigning class variables using functions, an alternative is to use a metaclass (it's kind of "annoying" and "magical" and I agree that the static method should be callable inside the class, but unfortunately it isn't). This way, we can refactor the behavior into a standalone function and don't clutter the class.
class KlassMetaClass(type(object)): @staticmethod def _stat_func(): return 42 def __new__(cls, clsname, bases, attrs): # Call the __new__ method from the Object metaclass super_new = super().__new__(cls, clsname, bases, attrs) # Modify class variable "_ANS" super_new._ANS = cls._stat_func() return super_new
class Klass(object, metaclass=KlassMetaClass): """ Class that will have class variables set pseudo-dynamically by the metaclass """ pass
print(Klass._ANS) # prints 42Using this alternative "in the real world" may be problematic. I had to use it to override class variables in Django classes, but in other circumstances maybe it's better to go with one of the alternatives from the other answers.