在深入研究元类之前,我试图了解 Python 类。我遇到了一些我无法弄清楚的代码。在这种情况下,类不使用 自我 而是类命名空间(没有使用 self 的选项,因此是这里的问题)。如何在一个类中定义一些命名空间变量,然后在子类中覆盖它们都依赖的值?
第一例
class B():
potato = "hey"
test = potato
#here would go a lot of more code that just depends on that potato value
class c(B):
B.potato = "not hey"
c_potato = c().test
print(c_potato)
它打印 嘿 .我明白是因为测试 指向字符串“hey”,该字符串不可变。换
B.potato = "not hey"
仅更改类命名空间 土 bean 到一个新的字符串,但它不会改变什么 测试 是指。所以我想,嘿,如果我用一个列表来做,那是引用吗?class B():
potato = ["hey"]
test = potato[0]
class c(B):
B.potato[0] = "not hey"
c_potato = c().test
print(c_potato)
在我看来,这应该有效。我没改什么土 bean 是指向,而是值(value)。不?但我明白它不会' 实际工作,因为 测试 指向 马铃薯[0] 而不仅仅是 土 bean .所以是的,我明白为什么这也会打印 嘿 .
我当时意识到,如果 测试 需要指向不可变的结果,那么我试图对命名空间做的事情是不可能的。
class B():
@staticmethod
def get_potato():
return "hey"
potato = get_potato.__func__
test = potato()
class c(B):
@staticmethod
def get_potato():
return "not hey"
B.potato = "6"
c_potato = c().test
print(c_potato)
我在这里更改了 整个 的值B.potato 但现在 测试 已经指向父项 的结果马铃薯() ,所以没关系,仍然打印出 “嘿” .
于是我想,可以元类 解决这个问题?显然是的,它可以。
class Meta(type):
def __new__(cls, name, bases, attrs):
x = super().__new__(cls, name, bases, attrs)
x.potato = "basic hey"
if 'meta_args' in attrs:
x.potato = attrs['meta_args'][0]
del attrs['meta_args'] # clean up
x.test = x.potato
return x
class A():
pass
class B(A, metaclass=Meta):
meta_args = ["super hey"]
pass
class C(B):
meta_args = ["not hey"]
b = B().test
c = C().test
print(b)
print(c)
并且正确打印 super 嘿发 b 和 不嘿为 c .问题是,这可以在没有元类的情况下完成吗?我的大脑在这一点上很痛。
最佳答案
您可能想要一个 @property
:
class B:
potato = 'hey'
@property
def test(self):
return self.potato
class C(B):
potato = 'not hey'
你所做的是分配
"hey"
至 test
以这种或那种方式。它的值不会改变,除非你真的给 test
分配了别的东西.通过使其成为 @property
,函数def test
每次访问时都会调用 .test
,所以它的值可以动态计算;在这种情况下,基于 potato
的值.子类声明自己的 potato
,它遮蔽了父级的 potato
属性(property)。
关于python - 覆盖父命名空间变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60813946/