Bypassing __setattr__ for changing special attributes

Steven D'Aprano steve at REMOVE.THIS.cybersource.com.au
Tue Feb 20 07:57:34 EST 2007


On Mon, 19 Feb 2007 23:18:02 -0800, Ziga Seilnacht wrote:

> George Sakkis wrote:
>> I was kinda surprised that setting __class__ or __dict__ goes through
>> the __setattr__ mechanism, like a normal attribute:
>>
>> class Foo(object):
>>     def __setattr__(self, attr, value):
>>         pass
>>
>> class Bar(object):
>>     pass
>>
>> >>> f = Foo()
>> >>> f.__class__ = Bar
>> >>> print f.__class__ is Foo
>> True
>>
>> Is there a way (even hackish) to bypass this, or at least achieve
>> somehow the same goal (change f's class) ?
>>
>> George
> 
>>>> object.__setattr__(f, '__class__', Bar)
>>>> f.__class__ is Bar
> True


This version is arguably more "correct", although a tad longer to write,
and doesn't need you to hard-code the class superclass:

super(f.__class__, f).__setattr__('__class__', Bar)


But what surprised me was that this *didn't* work:

>>> f = Foo()
>>> f.__dict__['__class__'] = Bar
>>> f.__class__
<class '__main__.Foo'>


Unless I'm confused, it looks like instance.__class__ bypasses the usual
lookup mechanism (instance.__dict__, then instance.__class__.__dict__) for
some reason.

>>> Foo.x = 1  # stored in class __dict__
>>> f.x
1
>>> f.__dict__['x'] = 2  # stored in instance __dict__
>>> f.x
2
>>> Foo.x
1

But __class__ doesn't behave like this. Why?



-- 
Steven.




More information about the Python-list mailing list