Make staticmethod objects callable?
Steven D'Aprano
steve at REMOVEMEcyber.com.au
Wed Mar 1 03:31:28 EST 2006
Nicolas Fleury wrote:
> Hi everyone,
> I was wondering if it would make sense to make staticmethod objects
> callable, so that the following code would work:
This is one of the more unintuitive areas of Python,
with side effects and different behaviour depending on
whether code is called inside or outside a class:
>>> class Parrot:
... def speak():
... return "dead parrot"
... speak = staticmethod(speak)
... def playdead():
... return "still dead"
...
>>> type(Parrot.speak)
<type 'function'>
>>> type(Parrot.playdead)
<type 'instancemethod'>
So, based on this evidence, staticmethod() converts an
instance method into an ordinary function. Parrot.speak
certainly behaves like an ordinary function.
>>> callable(Parrot.speak)
True
>>> Parrot.speak()
'dead parrot'
But now try to do the same outside of a class:
>>> f = staticmethod(Parrot.playdead)
>>> type(f)
<type 'staticmethod'>
f is not a function?
>>> Parrot.playdead = staticmethod(Parrot.playdead)
>>> type(Parrot.playdead)
<type 'instancemethod'>
So, based on this evidence, staticmethod() inside a
class definition converts instance methods to
functions. Outside a class definition, staticmethod()
does one of two things: it either converts an instance
method to a static method, or if the output is assigned
to a class attribute, it leaves it as an instance method.
Hmmm.
> class A:
> @staticmethod
> def foo(): pass
> bar = foo()
Here is a work around:
>>> class A:
... def foo(): return "foo foo foo"
... foo = staticmethod(foo)
... def __init__(self):
... if not hasattr(self.__class__, "bar"):
... self.__class__.bar = self.foo()
...
>>> dir(A)
['__doc__', '__init__', '__module__', 'foo']
>>> a = A()
>>> dir(A)
['__doc__', '__init__', '__module__', 'bar', 'foo']
>>> a.foo()
'foo foo foo'
>>> a.bar
'foo foo foo'
Here is a more interesting example:
>>> class B:
... def foo():
... return lambda x: x+1
... foo = staticmethod(foo)
... def __init__(self):
... if not hasattr(self.__class__, "bar"):
... self.__class__.bar = \
... staticmethod(self.foo())
...
>>> dir(B)
['__doc__', '__init__', '__module__', 'foo']
>>> b = B()
>>> dir(B)
['__doc__', '__init__', '__module__', 'bar', 'foo']
>>> b.foo()
<function <lambda> at 0xb7f70c6c>
>>> b.bar
<function <lambda> at 0xb7f70c34>
>>> b.bar(3)
4
Hope this helps.
--
Steven.
More information about the Python-list
mailing list