The reason you’re having problems with your static method usage as a default argument is due to a combination of two issues.
The first issue is that the default argument needs to be well defined when the
1def
statement is run, not only when the function is called. That’s because the default argument gets built into the function object, rather than being recalculated each time the function runs (this is the same reason why a mutable default argument like an empty list is often an error). Anyway, this is why you can’t use
1MyClass.static_method
as the default argument, since
1MyClass
isn’t defined yet when the function is being defined (the class object is only made after all its contents have been created).
The next issue is that a
1staticmethod
object doesn’t have all the same attributes and methods as a regular function. Normally this doesn’t matter, as when you access it through a class object (e.g.
1MyClass.static_method
once
1MyClass
exists) or through an instance (e.g.
1self.static_method
), it will be callable and have a
1__name__
. But that’s because you get the underlying function in those situations, rather than the
1staticmethod
object itself. The
1staticmethod
object itself is a descriptor, but not a callable.
So neither of these functions will work correctly:
1
2
3
4
5
6
7
8
9
10
11class MyClass:
@staticmethod
def static_method():
pass
def foo(self, func=MyClass.static_method): # won't work because MyClass doesn't exist yet
pass
def bar(self, func=static_method): # this declaration will work (if you comment out foo)
name = func.__name__ # but this doesn't work when the bar() is called
func() # nor this, as func is the staticmethod object
What does work would be to use the actual function underlying the
1staticmethod
object as the default:
1
2
3def baz(self, func=static_method.__func__): # this works!
name = func.__name__
func()
This also works when you pass in some other function (or bound method), unlike the version of your code that used
1name = func.__func__.__name__
.