In an inherited class, "embedded" classes is referenced?

Carl Banks pavlovevidence at gmail.com
Wed Dec 19 17:13:57 EST 2007


On Dec 19, 4:23 pm, Christian Joergensen <m... at razor.dk> wrote:
> Hello
>
> I stumpled upon this "feature" during my work tonight, and found it
> a bit confusing:
>
> >>> class A(object):
>
> ...     class C:
> ...         foobar = 42
> ...>>> class B(A): pass
> ...
> >>> A.C
>
> <class __main__.C at 0xb7cf735c>>>> B.C
>
> <class __main__.C at 0xb7cf735c>>>> B.C.foobar = 60
> >>> A.C.foobar
>
> 60
>
> When I inherit B from A, I would expect that A.C and B.C would be two
> different classes? But apparently not.

No, when a class inherits a class member from a subclass, both classes
reference the same object.  This is true of any object: classes,
lists, sets, etc.  For instance, if you were to do this,

class A(object):
    class C(object): pass
    d = [1,2,3,4]
    e = set(("a","b","c","d"))

class B(A):
    pass


Then you would find that

A.C is B.C
A.d is B.d
A.e is B.e

They are all the same object.

Perhaps you are misled by the example methods?  Even them, the same
function object is referenced by both classes.  The difference is,
when accessing a method, a class doesn't return the function object
itself, but a method object instead (which is a binding between a
function and a class, used to set the value of "self" when calling
it).

But only functions do something like that, not classes.


> Can anyone give me an explanation? Or a better workaround than
> something along the line of:
>
> >>> B.C = type("C", (object,), {'foobar': 60})

Well you could do this and not bother with the type call (but you'd
still have to do it by hand).

class B(A):
    class C(A.C):
        foobar = 60


Metaclass programming, or at least some clever properties, would be
required to do it automatically.  You could try something like this
(untested) to automatically subclass any class variables that are
instances of type:


class AutoSubclassMetaclass(type):
    def __new__(cls,name,bases,clsdict):
        for key,value in clsdict.iteritems():
            if isinstance(value,type):
                clsdict[key] = type(value.__name__,(value,),{})
        type.__new__(cls,name,bases,clsdict)


class A(object):
    __metaclasS__ = AutoSubclassMetaclass
    class C(object):
        foobar = 40

class B(A):
    pass


Carl Banks



More information about the Python-list mailing list