强制python子类init使用子类变量,而不是父类

时间:2012-07-20 14:39:42

标签: python

在以下代码中:

class A(object):
  VALUE = 1
  def __init__(self, value=VALUE):
    self.value = value

class B(A):
  VALUE = 2

我希望B()。值应该等于2,但是:

B().value = 1

是否有一种优雅的方法来定义一个类层次结构,其中子类只能声明它们想要覆盖的类变量并使它们成为实例变量的默认值?我仍然希望允许在每个实例级别更改这些,例如

b = B(value=3)

2 个答案:

答案 0 :(得分:10)

这是另一个default arguments问题。关键是你写的时候

def foo(value=VALUE):

函数内部的代码被编译并成为一个函数对象。它是在这个时间 - 而不是在通话时间! - 存储默认参数。因此,当您定义B时,为时已晚:默认值foo已设置,更改VALUE将不会产生任何影响。

如果这看起来很奇怪,假设foo是一个全局函数:

default = 3
def foo(x=default): pass

然后,任何地方的任何其他代码都可以通过执行

来搞砸foo
global default
default = 4

这可能同样令人困惑。


要强制在运行时完成查找而不是编译时间,你需要将它们放在函数中:

def foo(value=None):
    self.value = self.VALUE if value is None else value

或(不太相同但更漂亮)

self.value = value or self.VALUE

(这是不同的,因为它会将任何'falsy'值视为哨兵 - 即0[]{}等所有都被VALUE覆盖。)


编辑:@mgilson指出了另一种方法:

def foo(**kwargs):
    self.value = kwargs.get("value", self.VALUE)

这更简洁,因为它不需要你制作一个标记值(如Noneobject(),但它确实从根本上改变了foo的参数规范它将接受任意关键字参数。您的电话。

答案 1 :(得分:1)

不应在func声明行中定义默认值,否则,当python读取此行时,默认值将被聚焦,无论您稍后更改VALUE,默认值都不会更改。

您可以按如下方式编写:

class A:
    VALUE = 1
    def __init__(self, value=None):
        if value is None:
            value = self.VALUE
        self.value = value

class B(A):
    VALUE = 2

print(A().value)
print(B().value)