staticmethod and setattr

Andreas Löscher andreas.loescher at s2005.tu-chemnitz.de
Mon Mar 15 10:24:55 EDT 2010


Am Montag, den 15.03.2010, 05:42 -0700 schrieb Michael.Lausch:
> On Mar 15, 11:40 am, Steven D'Aprano <st... at REMOVE-THIS-
> cybersource.com.au> wrote:
> > On Mon, 15 Mar 2010 01:43:02 -0700, Michael.Lausch wrote:
> > > Hi,
> >
> > > I managed to get confused by Python, which is not such an easy task.
> >
> > > The problem i have is rooted in marshalling, JSON and Dojo. I need some
> > > static class in function with the name "$ref" i tried:
> > > class Foo(object):
> > >     @staticmethod
> > >     def _ref(o):
> > >          pass
> >
> > > setattr(Foo, "$ref", Foo._ref)
> >
> > That doesn't work as expected:
> >
> > >>> Foo.__dict__['_ref'] is Foo.__dict__['$ref']
> >
> > False
> >
> > Try this instead:
> >
> > >>> setattr(Foo, "$ref", Foo.__dict__['_ref'])
> > >>> Foo.__dict__['_ref'] is Foo.__dict__['$ref']
> >
> > True
> 
> Now I'm trying to understand why this is the case.
> How is Foo.__dict__['_ref']  different from Foo._ref?
> Shouldn't it return the same attribute?
> 
> And after further experiments i found out that a making
> Foo._ref a classmethod does work with my first approach.
> 

In the class dictionary are the "raw" objects stored. For example:

class Spam:
    @staticmethod
    def egg1():
        pass
    def egg2(self):
        pass

>>> Spam.__dict__
{'egg1': <staticmethod object at 0x7f0b03240b40>, '__module__':
'__main__', 'egg2': <function egg2 at 0x7f0b0432a2a8>, '__doc__': None}

If you try to call egg1 as staticmethod you will get an error:
>>> Spam.__dict__['egg1']()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'staticmethod' object is not callable

getattr() is not only a shortcut for the line above. It searches all
base classes for the specified name in the class dictionaries. If the
name is found, and the object has an additional descriptor, it is
applied on the object itself.

In case of an static method, the descriptor sm_descr_get is located in
Objects/funcobjects.c of the sources and it retriefes the encapsuled
callable, which in this case is the function egg1.

If you now set the function as new attribute, it is no longer a static
method, but a normal function. If a function is retrieved via getattr(),
it is encapsuled in an method object. (func_descr_get in the same file)
If you now try to call the method in you example, you call a method from
a class. This results in an unbound method, which requests an instance
of the class as first agument. 

I hope this clears some things up.

Best
Andreas




More information about the Python-list mailing list