Question

I'm trying to design a class structure where the bases of a class are determined at runtime. With a great many thanks to the answer to this question about metaclasses, it clicked that the type function can be made to do this by constructing the tuple of bases at runtime. Excellent.

Now that opens a possibility that I'm not sure I'm comfortable with-- through some sequence of operations I could wind up with the equivalent to:

X  = type('X', (object,), {})
Y  = type('Y', (X,), {})
Y2 = type('Y', (object,), {})

I now have two classes (Y and Y2) with different inheritance structures but both share the classname 'Y'.

c  =  y.__class__
c2 = y2.__class__

(c,c2)                      #returns  (__main__.Y, __main__.Y)
(c.__bases__,c2.__bases__)  #returns  ((__main__.X,), (object,))

It appears from this, that the classname is just an arbitrary string for human consumption, and Python takes the view that if I want to go and confuse myself, I'm welcome to.

Is that correct? Are there pitfalls awaiting me elsewhere in the bowels of Python if different classes are allowed to share the same name?

Was it helpful?

Solution

I can't comment on why you'd want to do something like this, but if you do need such dynamic behavior, perhaps consider using a metaclass to accomplish your goal?

Regardless, if you're wondering whether using the same class name will cause problems later on (I'm assuming you mean problems other than maintainability - as others have said, this has a high potential of being confusing and unnecessarily complex), then no, it won't.

The documentation for type() is pretty clear about what the arguments are for:

The name string is the class name and becomes the __name__ attribute; the bases tuple itemizes the base classes and becomes the __bases__ attribute; and the dict dictionary is the namespace containing definitions for class body and becomes the __dict__ attribute

That description shows that the name is simply used to populate a __name__ field. It turns out that it's basically for the humans, as shown in another answer.

In fact, you don't even need to use type() to do this - you can do it with the simple class statement.

class X(object): pass
class Y(object): pass

def create_other_y():
    class Y(X): pass
    global Y2
    Y2 = Y

create_other_y()

(Y, Y2)                      # => (__main__.Y, __main__.Y)
(Y.__bases__, Y2.__bases__)  # => ((object,), (__main__.X,))

OTHER TIPS

The class name is not required to have any relation to the name of the variable you store it in. You can get the same behavior with a class statement and an assignment:

class Y(Base1): pass
Y2 = Y
class Y(Base2): pass

This happens in practice with things like decorators, if you don't update the returned object's metadata:

def decorate(klass):
    class DecoratedClass(klass):
        def stuff(self):
            do_whatever()
    return klass

@decorate
class Foo(object): pass

@decorate
class Bar(object): pass

After this code, the Foo and Bar variables refer to two classes named DecoratedClass with different inheritance hierarchies.

Python assigns no special significance to the class name. It's mostly there for humans to see. If you do this, Python will have no problems with it. The people who have to maintain the code might, though.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top