同模块中两个类同名但基类不同?

2 投票
2 回答
1507 浏览
提问于 2025-04-17 22:30

我正在尝试设计一个类的结构,让类的基类在运行时决定。非常感谢关于元类的问题的回答,我明白了可以通过在运行时构建基类的元组来使用type函数。太棒了。

这让我想到一个我不太确定是否能接受的可能性——通过一系列操作,我可能会得到类似于:

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

现在我有两个类(YY2),它们的继承结构不同,但它们的类名都是'Y'

c  =  y.__class__
c2 = y2.__class__

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

从这里看,类名似乎只是一个供人类使用的任意字符串,而Python的态度是,如果我想让自己困惑,那就随便我。

这样理解对吗?如果不同的类可以共享相同的名字,Python的其他地方会有潜在的问题吗?

2 个回答

3

类的名字和你用来存储它的变量名没有必要有任何关系。你可以通过一个 class 语句和一个赋值来实现相同的效果:

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

在实际操作中,像装饰器这样的东西就会出现这种情况,如果你不更新返回对象的元数据:

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

@decorate
class Foo(object): pass

@decorate
class Bar(object): pass

在这段代码执行后,FooBar 这两个变量分别指向两个名为 DecoratedClass 的类,但它们的继承结构是不同的。

Python 对类名没有特别的要求。类名主要是给人类看的。如果你这样做,Python 是不会有问题的。不过,维护代码的人可能会觉得麻烦。

4

我不能评论你为什么想这样做,但如果你确实需要这种动态的行为,也许可以考虑使用元类来实现你的目标?

无论如何,如果你在担心使用相同的类名会不会在以后造成问题(我假设你指的不是可维护性的问题——正如其他人所说,这样做很可能会让事情变得混乱和复杂),那么答案是不会的。

关于type()的文档对参数的说明很清楚:

名称字符串是类名,并成为__name__属性;基类元组列出了基类,并成为__bases__属性;字典则是包含类体定义的命名空间,并成为__dict__属性。

这个描述表明,名称只是用来填充__name__字段。实际上,这基本上是为了人类理解,如另一条回答所示。

事实上,你甚至不需要使用type()来做到这一点——你可以直接用简单的class语句来实现。

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,))

撰写回答