Assigning to __class__ attribute

Robert Kern robert.kern at gmail.com
Fri Dec 3 15:57:56 EST 2010


On 12/3/10 1:28 PM, kj wrote:
>
>
> I have a couple of questions regarding assigning to an instance's
> __class__ attribute.
>
> The first is illustrated by the following interaction.  First I
> define an empty class:
>
>>>> class Spam(object): pass
> ...
>
> Now I define an instance of Spam and an instance of Spam's superclass:
>>>> x = Spam()
>>>> y = Spam.__mro__[1]() # (btw, is there a less uncouth way to do this???)
>>>> [z.__class__.__name__ for z in x, y]
> ['Spam', 'object']
>
> Now I define a second empty class:
>>>> class Ham(object): pass
> ...
>
> Next, I attempt to assign the value Ham to x.__class__:
>
>>>> x.__class__ = Ham
>>>> [isinstance(x, z) for z in Spam, Ham]
> [False, True]
>
> This was the first surprise for me: assigning to the __class__
> attribute not only isn't vetoed, but in fact changes the instances
> class:
>
> Oh-kaaaay...
>
> First question: how kosher is this sort of class transmutation
> through assignment to __class__?  I've never seen it done.  Is this
> because it considered something to do only as a last resort, or is
> it simply because the technique is not needed often, but it is
> otherwise perfectly ok?

Last resort for very special purposes, and only extremely rarely in production.

> The second, and much bigger, surprise comes when I attempt to do
> the same class-switching with y:
>
>>>> y.__class__ = Ham
> Traceback (most recent call last):
>    File "<stdin>", line 1, in<module>
> TypeError: __class__ assignment: only for heap types
>
> (If you recall, y's class is object, the superclass of x.) Apparently
> Spam is a "heap type" (whatever that is) but its superclass, object,
> isn't.  This definitely rattles my notions of inheritance: since
> the definition of Spam was empty, I didn't expect it to have any
> significant properties that are not already present in its superclass.
> What's going on here? Is this a bug, or a feature? I can see no
> logical justification for allowing such class switching for only
> some class and not others.

Feature. When you have C-implemented types, you cannot safely swap out their 
instance's __class__. There are memory issues involved. Only subclasses of 
object made by the class statement (or the equivalent type(...) call), i.e. 
"heap types", permit this modification. object is a C-implemented type. 
Importantly, as for most other C-implemented types, plain object instances have 
no __dict__.

Types and classes were unified a long time ago in Python 2.2, but there are 
still relevant distinctions between C-implemented types and Python-implemented 
types.

> One last question:  as the questions above make clear, I have a
> colossal muddle inside my head regarding Python's model of classes
> and inheritance.  This is not for lack of trying to understand it,
> but, rather, for exactly the opposite reason: in my zeal to gain
> the fullest understanding of this topic, I think I have read too
> much that is incorrect, or obsolete, or incomplete...
>
> What is the most complete, definitive, excruciatingly detailed
> exposition of Python's class and inheritance model?  I'm expressly
> avoiding Google to answer this question, and instead asking it
> here, because I suspect that there's some connection between my
> state of utter confusion on this topic and the ease with which the
> complete/definitive/highest-quality information can get lost among
> a huge number of Google hits to popular-but-only-partially-correct
> sources of information.  (In fact, I *may* have already read the
> source I'm seeking, but subsequent readings of incorrect stuff may
> have overwritten the correct information in my brain.)

http://www.python.org/download/releases/2.2.3/descrintro/

-- 
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
  that is made terrible by our own mad attempt to interpret it as though it had
  an underlying truth."
   -- Umberto Eco




More information about the Python-list mailing list