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

(これは、「偽の」値を番兵として扱うため、異なります。つまり、、0など[]{}すべて。で上書きされVALUEます。)


編集:@mgilsonはこれを行う別の方法を指摘しました:

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

これは、番兵の値(Noneまたはなど)を作成する必要がないという点で優れていますが、任意のキーワード引数を受け入れるようになったため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 に答える