Behavior of staticmethod in Python 3
steve+comp.lang.python at pearwood.info
Sun Nov 24 15:18:07 CET 2013
On Sun, 24 Nov 2013 11:30:14 +0100, Antoon Pardon wrote:
> Foo.foo() is legal here. So Foo.foo is callable.
Incorrect. Foo.foo() is legal for *any* identifiers Foo and foo. Since
Python is an extremely dynamic language, the compiler cannot (easily, or
at all) prohibit "illegal" combinations. The only combinations which are
illegal are those which are not legal identifier, e.g.:
Otherwise, any pair of legal identifiers are legal and will be accepted
by the compiler. Only at runtime does the lookup succeed or fail:
str.length # likely to fail, unless str has been shadowed
str.find # likely to succeed, unless str has been shadowed
If the lookup has succeeded, then and only then does a second lookup
and if that succeeds it is called.
It isn't helpful to talk about function or method calls being "legal" or
"illegal" in Python, since such things are normally determined in terms
of *success* or *failure*, not permitted versus prohibited. Either the
full chain of lookups and function call will succeed, or something will
raise an exception and it will fail.
> Foo.foo() being legal and Foo.foo not being callable is IMO a bug in
> python. No matter what explanation you have for the behaviour.
I don't know why you keep going on about this point, since this is NOT
the behaviour the original poster is talking about. With foo decorated as
a staticmethod in class Foo, Foo.foo *is* callable. It takes 30 seconds
to try it yourself:
py> class Foo(object): # inherit from object necessary in Python 2
... def foo():
... return "Success!"
This is not what the OP is talking about. Try this instead:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'staticmethod' object is not callable
What's going on here? Let's have a look:
<staticmethod object at 0x9d83194>
<function foo at 0x9d80294>
You CANNOT understand this behaviour without understanding the descriptor
protocol, which is *fundamental* to Python, and has been since Python
2.2. Regular instance methods, class methods, static methods and
properties are all defined in terms of descriptors. Trying to understand
them without knowledge of descriptors is like trying to understand
generators and iterators without knowledge of StopIteration -- you can go
only so far before you get stuck and confused.
The OP discovered that you can call a regular function inside a class
body, outside of a method, during the class statement:
attr = function()
This works, but then you can't call MyClass().function() as it will
raise. So the OP tried making it a staticmethod:
attr = function()
but that fails, because *staticmethod instances are not callable*. They
are descriptors. Only after the descriptor protocol gets a chance to run
do you get a callable function.
*This is not a bug.* Making staticmethod instances callable is a feature
enhancement, not a bug fix. Or you could just define your own callable-
staticmethod descriptor, it's easy enough to do.
More information about the Python-list