[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.python

Re: staticmethod and setattr

Andreas Löscher

3/15/2010 2:25:00 PM

Am Montag, den 15.03.2010, 05:42 -0700 schrieb Michael.Lausch:
> On Mar 15, 11:40 am, Steven D'Aprano <st...@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

1 Answer

Jean-Michel Pichavant

3/15/2010 6:25:00 PM

0

Am Montag, den 15.03.2010, 05:42 -0700 schrieb Michael.Lausch:
>> On Mar 15, 11:40 am, Steven D'Aprano <st...@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.
>>
>>

When you declared _ref as static, a static object has been stored in Foo.
Using Foo.__dict__ you can access this static object, which is *not* the
_ref function
Using Foo._ref, you trigger the lookup mechanism which do much more than
accessing the dict. Especially, if it finds a __get__ method in the
object, it will return the __get__ result instead of the object itself.

Foo._ref is equivalent in your case to
Foo.__dict__['_ref'].__get__(None, Foo)


JM