Class.__class__ magic trick help

Massimo Di Pierro massimo.dipierro at gmail.com
Mon Aug 20 15:28:51 EDT 2012


The fact is this works:

>>> class B(object):
...    __class__ = dict
>>> b=B()

but this does not

>>> class B(object):
...    def __init__(self):
...        self.__class__ = dict
>>> b=B()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
TypeError: __class__ assignment: only for heap types



On Aug 20, 1:39 pm, Ian Kelly <ian.g.ke... at gmail.com> wrote:
> On Mon, Aug 20, 2012 at 12:01 PM, Massimo Di Pierro
>
> <massimo.dipie... at gmail.com> wrote:
> > I discovered I can do this:
>
> >     class A(object): pass
> >     class B(object):
> >         __class__ = A # <<<< magic
>
> >     b = B()
> >     isinstance(b,A) # returns True (as if B derived from A)
> >     isinstance(b,B) # also returns True
>
> > I have some reasons I may want to do this (I an object with same
> > methods as a dict but it is not derived from dict and I want
> > isinstance(x,dict)==True to use it in place of dict in some other
> > code).
>
> > What are the problems with the magic trick above? Why does it work?
>
> Normally with __class__ assignment, you would assign to the __class__
> attribute of the *instance*, not the class declaration.  This actually
> changes the class of the object, and so isinstance(b, B) would no
> longer return True.
>
> I've never heard of assigning it in the class declaration, and as far
> as I know, this behavior isn't documented anywhere.  I expect that
> what's happening here is that Python is not actually updating the
> class of the instance, but that A is merely assigned to the
> "__class__" attribute in the class dict, and that isinstance is
> somehow (perhaps accidentally) finding this.  So I think this is
> probably a bug, and I would not rely on it to work correctly in all
> cases.
>
> In any event, the use case that you're looking for is usually
> accomplished using abstract base classes.  Instead of "isinstance(x,
> dict)", you should use "isinstance(x, collections.MutableMapping)",
> and then inherit your class from or register it with the
> MutableMapping ABC.




More information about the Python-list mailing list