Static method object not callable

Bengt Richter bokr at oz.net
Wed Aug 11 00:48:56 EDT 2004


On Wed, 11 Aug 2004 02:40:07 GMT, "Edward Diener" <eldiener at earthlink.net> wrote:

>Paul Morrow wrote:
>> Edward Diener wrote:
>>> This simple code example gives me the message, "TypeError:
>>> 'staticmethod' object is not callable".
>>>
>>> class X(object):
>>>   def Y(x):
>>>     print x
>>>   Y = staticmethod(Y)
>>>   ad = { 1 : Y }
>>>   def Z(self):
>>>     self.ad[1](3)
>>> x = X()
>>> x.Z()
>>> print "Done."
>>>
>>> I know there must be a way to have a class attribute reference a
>>> static method, and then call that static method through the
>>> reference, so if anyone can correct this it would be appreciated.
By 'reference' are you referring to the Y in ad?
>>>
>>>
>>>
>>
>> Here are two alternatives. snip...
>
>Neither alternative is satisfactory. Surely there must be some means of
>directly specifying a reference to a static method in a class attribute in
>Python, and calling it from an instance method through the class attribute.
>
>
I'm not sure what you really want, but a staticmethod object is UIAM a descriptor
and when descriptors are retrieved as attributes of something, their __get__ methods
are called. That's why getattr was part of the other alternatives. Alternatively,
you can call the __get__ method directly, and in the case of staticmethod, that
will get you back the unadorned function in question, which you can then call. E.g.,

 >>> class X(object):
 ...   def Y(x):
 ...     print x
 ...   Y = staticmethod(Y)
 ...   ad = { 1 : Y }
 ...   def Z(self):
 ...     self.ad[1].__get__(self, type(self))(3)
 ...
 >>> x = X()
 >>> x.Z()
 3

(BTW, for staticmethod.__get__, probably any argument(s)
other than None or None,None will work)

Maybe this will clarify a little:

A function also works like a descriptor, and has a __get__ method, which is called
to create a bound method when the function is retrieved as an attribute of an
object instance. Note that Z is a function with one argument (self).

When retrieving Z as attribute of the class, the __get__ method gets
the arguments __get__(None, X), which gets you the unbound method.

 >>> X.Z
 <unbound method X.Z>

If we bypass the attribute access mechanism, we get the function itself:
 >>> X.__dict__['Z']
 <function Z at 0x009062B0>

If we do the getattr mechanics manually, calling the __get__ of the function,
we see the method results corresponding to X.Z and x.Z respectively:

 >>> X.__dict__['Z'].__get__(None, X)
 <unbound method X.Z>
 >>> X.__dict__['Z'].__get__(x, X)
 <bound method X.Z of <__main__.X object at 0x009011D0>>

We can make a hokey descriptor object to show this:
 >>> class Desc(object):
 ...     def __get__(*args): print args
 ...
 >>> class C(object):
 ...     attr = Desc()
 ...
 >>> c = C()
 >>> C.attr
 (<__main__.Desc object at 0x009015D0>, None, <class '__main__.C'>)
 >>> c.attr
 (<__main__.Desc object at 0x009015D0>, <__main__.C object at 0x00901950>, <class '__main__.C'>)

So the __get__ args are the self of the decriptor instance itself (handy for carrying baggage like
a function), and here either None,C or c,C for C.attr and c.attr repectively.

Y is a staticmethod object though, not a plain function.
The __get__ method of a staticmethod object returns the same thing
(the original function) for either kind of call.
So when retrieved as an attribute of something, you get the function in question:

 >>> X.Y
 <function Y at 0x008FDF70>
 >>> x.Y
 <function Y at 0x008FDF70>

Bypassing attribute mechanism:
 >>> X.__dict__['Y']
 <staticmethod object at 0x00901110>

Doing it manually bound-method style or unbound-method style:
 >>> X.__dict__['Y'].__get__(x, X)
 <function Y at 0x008FDF70>
 >>> X.__dict__['Y'].__get__(None, X)
 <function Y at 0x008FDF70>

Calling the retrieved function:
 >>> X.__dict__['Y'].__get__(x, X)(123)
 123

Of course,
 >>> X.Y(456)
 456
 >>> x.Y(456)
 456

or
 >>> getattr(X,'Y')(789)
 789
 >>> getattr(x,'Y')(789)
 789

I still don't know what you are really trying to do with that
Z method and the ad dict ;-)

Regards,
Bengt Richter



More information about the Python-list mailing list