Behavior of staticmethod in Python 3
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Sat Nov 23 08:48:52 EST 2013
On Sat, 23 Nov 2013 09:28:43 +0100, Marco Buttu wrote:
> In Python 3 the following two classes should be equivalent:
They certainly are not equivalent in *any* version of Python, because
staticmethods are not equivalent to instance methods.
> $ cat foo.py
> class Foo:
> def foo():
> pass
> print(callable(foo))
>
> class Foo:
> @staticmethod
> def foo():
> pass
> print(callable(foo))
>
> But they do not:
>
> $ python3 foo.py
> True
> False
And Python 2 gives the same result for staticmethods:
[steve at ando ~]$ python2.7
Python 2.7.2 (default, May 18 2012, 18:25:10)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-52)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
py>
py> class Test(object):
... @staticmethod
... def method():
... pass
... print callable(method)
...
False
> How come the metaclass does not skip the staticmethod decorator?
What makes you think the metaclass gets the opportunity to skip the
decorator? By the time the metaclass gets called, the decorator has
already run.
You seem to be conflating behaviour in Python 2 that doesn't actually
occur. Staticmethods are not directly callable in any version of Python.
The problem you seem to have is that you want to call a method both
during and after construction:
class MyClass(object):
def helper(arg):
return arg + 1
x = helper(10)
y = helper(20)
def method(self, arg):
return self.helper(arg)
Here, the attributes x and y rely on calling helper as a function, where
it does not receive a self argument, but when calling helper from inside
the instance method, or when calling it like MyClass.helper(), it will
receive a self argument.
Unfortunately there is no good solution to this using just built-ins.
staticmethod doesn't work, as it's not callable. However, we can create
our own callable version of staticmethod:
class callable_staticmethod(object):
def __init__(self, func):
self.func = func
def __get__(self, obj, cls=None):
return self.func
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)
class MyClass(object):
@callable_staticmethod
def helper(arg):
return arg + 1
x = helper(10)
y = helper(20)
def method(self, arg):
return self.helper(arg)
This should now work exactly as you hope.
--
Steven
More information about the Python-list
mailing list