【发布时间】:2020-07-03 22:32:12
【问题描述】:
在深入研究元类之前,我试图了解 Python 类。我遇到了一些我无法弄清楚的代码。在这种情况下,类不使用 self 而是使用类命名空间(没有使用 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)
它会打印 嘿。我理解,因为 test 指向字符串“hey”,它是不可变的。更改 B.potato = "not hey" 只会将类命名空间 potato 更改为新字符串,但不会更改 test 指向的内容。所以我想,嘿,如果我用一个列表来做,那是通过引用来做的吗?
class B():
potato = ["hey"]
test = potato[0]
class c(B):
B.potato[0] = "not hey"
c_potato = c().test
print(c_potato)
在我看来,这应该有效。我没有改变 potato 所指的内容,而是改变了价值。不?但我知道它 不会' 真正起作用,因为 test 指向 potato[0] 而不仅仅是 potato .所以,是的,我明白为什么这也会打印 hey。
那时我意识到,如果 test 需要指向结果,它是不可变的,那么我试图用命名空间做的事情是不可能的。
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 的 entire 值,但现在 test 已经指向父母 的结果土豆(),所以没关系,仍然打印出“嘿”。
然后我想,元类可以解决这个问题吗?显然是的,它可以。
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 hey fo b 和 not hey for c。问题是,这可以在没有元类的情况下完成吗?这会儿我的脑子很疼。
【问题讨论】:
-
B.potato = "not hey"在class中一开始没有多大意义。 -
您的基本误解似乎是这里没有任何东西指向。
test是值"hey"。您正在以各种方式将"hey"与test联系起来,仅此而已。然后你永远不会给它分配任何其他东西,所以它保持这种状态。如果您希望.test属性根据其他内容动态解析,您可能希望将其设为@property?! -
你大部分时间都在为那里的变量赋值而战,而在类或元类应该做的事情上做的很少。只是不要去那里。
标签: python namespaces metaclass