假设我们有一个基类A
,它包含一些类变量。这个类还有一个类方法foo
,对这些变量执行一些操作。由于这种行为不应该被硬编码(例如,我们不希望在添加新的类变量时必须修改foo
(,foo
读取cls.__dict__
,而不是直接引用变量
现在我们介绍一个派生类:B
用更多的类变量扩展了A
,并继承了foo
。代码示例:
class A:
x = 0
y = 1
@classmethod
def foo(cls):
print([name for name, prop in cls.__dict__.items() if type(prop) is int])
class B(A):
z = 3
print(B.x) # prints "0"
A.foo() # prints "['x', 'y']"
B.foo() # prints "['z']" -- why not "['x', 'y', 'z']"?
因此,我的问题是:为什么B.__dict__
不包含从A
继承的变量,如果不包含,那么它们在哪里?
这与在实例方法中从父类访问类属性不同,因为我不想查询基类中的特定变量,我想在不知道它们名称的情况下列出它们。这个问题中给出的与MRO相关的答案可能也适用于这里,但在我看来,最初的问题不同。
我用元类解决了这个问题,用它来重新定义派生类的创建方式。在这种方法中,我们感兴趣的所有类变量都从基类复制到派生类:
class M(type):
def __new__(cls, name, bases, dct):
for base in bases:
for name, prop in base.__dict__.items():
if type(prop) is int:
dct[name] = prop
return super(M, cls).__new__(cls, name, bases, dct)
class A(metaclass=M):
x = 0
y = 1
@classmethod
def foo(cls):
print([name for name, prop in cls.__dict__.items() if type(prop) is int])
class B(A):
z = 3
A.foo() # prints "['y', 'x']"
B.foo() # prints "['y', 'x', 'z']"
此外,元类的定义方式可以使foo
甚至不必查询__dict__
——如果出于某种原因必须避免,则可以将感兴趣的变量放入列表中,而不是修改__dict__
。