4

在以下代码中:

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

class B(A):
  VALUE = 2

我希望 B().value 应该等于 2,但是:

B().value = 1

有没有一种优雅的方式来定义一个类层次结构,其中子类可以只声明他们想要覆盖的类变量并将它们作为实例变量的默认值?我仍然希望允许在每个实例级别上更改这些,例如。

b = B(value=3)
4

2 回答 2

10

这是另一个默认参数问题。关键是当你写

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)

这更简洁,因为它不需要您创建标记值(例如Noneor object(),但它确实从根本上改变了参数规范,foo因为现在它将接受任意关键字参数。您的电话。

于 2012-07-20T14:43:35.653 回答
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)
于 2012-07-20T14:59:12.717 回答