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