1. ホーム
  2. python

[解決済み] データクラスは、なぜクラス属性宣言で変更可能なデフォルトを持つことができないのですか?

2023-02-17 05:08:55

質問

これは は、以前にも質問されたことがあるような気がしますが、1 時間ほど検索しても結果は得られませんでした。 データクラスにデフォルトのリスト引数を渡す は有望に見えましたが、私が探しているものではありません。

ここに問題があります: クラス属性に変更可能な値を割り当てようとすると、エラーが発生します。

@dataclass
class Foo:
    bar: list = []

# ValueError: mutable default <class 'list'> for field a is not allowed: use default_factory

エラーメッセージから察するに、代わりに以下のようにすればいいようです。

@dataclass
class Foo:
    bar: list = field(default_factory=list)

しかし、なぜ変更可能なデフォルトは許されないのでしょうか?それは 変更可能なデフォルトの引数の問題 ?

どのように解決するのですか?

私の疑問は、かなり明確に ドキュメント (から派生したものです)。 PEP 557 から派生したものです)。

Pythonはメンバー変数のデフォルト値をクラス属性に保存します。データクラスを使用しないこの例を考えてみましょう。

class C:
    x = []
    def add(self, element):
        self.x.append(element)

o1 = C()
o2 = C()
o1.add(1)
o2.add(2)
assert o1.x == [1, 2]
assert o1.x is o2.x

クラスの2つのインスタンス C は同じクラス変数 x は、予想通り

データクラスを使用して、このコードが有効であった場合。

@dataclass
class D:
    x: List = []
    def add(self, element):
        self.x += element

のようなコードが生成されるでしょう。

class D:
    x = []
    def __init__(self, x=x):
        self.x = x
    def add(self, element):
        self.x += element

これは、元の例と同じ問題で、クラス C . つまり、2つのクラス D に値を指定しない x を指定しなかった場合、クラスインスタンスの作成時に x . データクラスは通常のPythonのクラス作成を使用するだけなので、彼らもこの動作を共有します。データクラスがこの状態を検出する一般的な方法はありません。その代わりに、データクラスは ValueError 型のデフォルトパラメータを検出した場合 list , dict または set . これは部分的な解決策ですが、多くの一般的なエラーから保護することができます。