Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Bypassing __setattr__ for changing special attributes

Reply
Thread Tools

Bypassing __setattr__ for changing special attributes

 
 
George Sakkis
Guest
Posts: n/a
 
      02-20-2007
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

 
Reply With Quote
 
 
 
 
Ziga Seilnacht
Guest
Posts: n/a
 
      02-20-2007
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

Ziga

 
Reply With Quote
 
 
 
 
bruno.desthuilliers@gmail.com
Guest
Posts: n/a
 
      02-20-2007
On 20 fév, 05:39, "George Sakkis" <(E-Mail Removed)> wrote:
> I was kinda surprised that setting __class__ or __dict__ goes through
> the __setattr__ mechanism, like a normal attribute:


But __class__ and __dict___ *are* 'normal' attributes...


 
Reply With Quote
 
Steven D'Aprano
Guest
Posts: n/a
 
      02-20-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.

 
Reply With Quote
 
George Sakkis
Guest
Posts: n/a
 
      02-20-2007
On Feb 20, 3:54 am, "(E-Mail Removed)"
<(E-Mail Removed)> wrote:
> On 20 fév, 05:39, "George Sakkis" <(E-Mail Removed)> wrote:
>
> > I was kinda surprised that setting __class__ or __dict__ goes through
> > the __setattr__ mechanism, like a normal attribute:

>
> But __class__ and __dict___ *are* 'normal' attributes...


Well, let alone for the fact that two leading and trailing underscores
means 'special' in python, these attributes are not exactly what they
seem to be, i.e. a 'normal' type or dict:

>>> type(object.__dict__['__class__'])

<type 'getset_descriptor'>
>>> type(type.__dict__['__dict__'])

<type 'getset_descriptor'>


George

 
Reply With Quote
 
George Sakkis
Guest
Posts: n/a
 
      02-20-2007
On Feb 20, 7:57 am, Steven D'Aprano
<(E-Mail Removed)> wrote:
> 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.


Perhaps because __class__ is a special descriptor:

>>> type(object.__dict__['__class__'])

<type 'getset_descriptor'>

George

 
Reply With Quote
 
Fuzzyman
Guest
Posts: n/a
 
      02-21-2007
On Feb 20, 12:57 pm, Steven D'Aprano
<(E-Mail Removed)> wrote:
> 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?
>


Magic attributes like __class__ are looked up on the class rather than
the instance.

Fuzzyman
http://www.voidspace.org.uk/python/articles.shtml

> --
> Steven.



 
Reply With Quote
 
Facundo Batista
Guest
Posts: n/a
 
      02-27-2007
Ziga Seilnacht wrote:


>>>> object.__setattr__(f, '__class__', Bar)
>>>> f.__class__ is Bar

> True


Interesting, but... why I must do this? And, I must *always* do this?

With Foo and Bar like the OP coded (just two new style classes, f is
instance of Foo), see this:

>>> f

<__main__.Foo object at 0xb7d1280c>
>>> setattr(f, '__class__', Bar)
>>> f

<__main__.Foo object at 0xb7d1280c>


Ok, didn't work, try your way:

>>> object.__setattr__(f, '__class__', Bar)
>>> f

<__main__.Bar object at 0xb7d1280c>


Wow! Ok, but getting back to Foo, with the *former* method:

>>> setattr(f, '__class__', Foo)
>>> f

<__main__.Foo object at 0xb7d1280c>


I can't explain this to myself,

Regards,

--
.. Facundo
..
Blog: http://www.taniquetil.com.ar/plog/
PyAr: http://www.python.org/ar/



 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Setting an attribute without calling __setattr__() Joshua Kugler Python 12 04-29-2008 07:20 PM
Mixing custom __setattr__ method and properties in new style classes L.C. Rees Python 3 02-08-2006 05:35 PM
__getattr__, __setattr__ Thomas Heller Python 3 10-20-2005 04:50 PM
Recursion with __setattr__ Chris Young Python 0 10-16-2005 07:55 AM
__setattr__ and __getattr__ with derived classes Anand Python 0 12-18-2003 09:36 PM



Advertisments