首页 > 解决方案 > 覆盖父命名空间变量

问题描述

在深入研究元类之前,我试图了解 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"只会将类命名空间土豆更改为新字符串,但不会更改测试指向的内容。所以我想,嘿,如果我用一个列表来做,那是通过引用来做的吗?

class B():
    potato = ["hey"]
    test = potato[0]

class c(B):
    B.potato[0] = "not hey"

c_potato = c().test
print(c_potato)

在我看来,这应该有效。我没有改变土豆指向的东西,而是改变了价值。不?但我知道它实际上不会起作用,因为test指向的是potato[0]而不是只是potato。所以是的,我明白为什么这也会打印hey

那时我意识到,如果测试需要指向不可变的结果,那么我试图用命名空间做的事情是不可能的。

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的整个值,但现在test已经指向父母的结果potato(),所以没关系,仍然打印出"hey"

然后我想,元类可以解决这个问题吗?显然是的,它可以。

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不是 hey for c。问题是,这可以在没有元类的情况下完成吗?此时我的大脑很痛。

标签: pythonnamespacesmetaclass

解决方案


你可能想要一个@property

class B:
    potato = 'hey'

    @property
    def test(self):
        return self.potato


class C(B):
    potato = 'not hey'

你所做的是以一种或另一种方式分配"hey"给的。test除非您实际上将其他内容分配给test. 通过将其设为 a ,每次访问时都会调用@property该函数,因此可以动态计算其值;在这种情况下,基于 的值。子类声明了自己的,它隐藏了父类的属性。def test.testpotatopotatopotato


推荐阅读