3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Pythonのdataclassの落とし穴

Last updated at Posted at 2020-11-26

落とし穴: クラスを作りなおしても前のクラスのデータを持っている

このコードを走らせたときにハマった。

from dataclasses import dataclass, field
from typing import List


@dataclass
class Struct:
    x: str


@dataclass
class Container:
    content: List[Struct] = field(default_factory=list)


@dataclass
class ContainerWrapper:
    container: Container = Container()

    def append(self, s: Struct) -> None:
        self.container.content.append(s)
        return None

    def store_structs(self, s_list: List[Struct]) -> None:
        for s in s_list:
            self.append(s)
        return None

s_list = [Struct("foo")]
ContainerWrapper().store_structs(s_list)
# recreated instance strangely contains old instance's data.
wrapper = ContainerWrapper()
print(wrapper.container) #=> Container(content=[Struct(x='foo')])

なんでContentainerWrapperクラスを作り直したあとも作り直す前のインスタンスのデータを持っとるんやってなっでハマった。

種明かし: 実は@dataclassに問題があるみたい

Pythonのドキュメントでは、@dataclassデコレータを用いてデフォルトの値を設定すると、 __init__()でデフォルト値を設定したのと同じように、インスタンス変数に値が代入されると主張している。

すなわち、以下の2つのコードは等価であるはずだ。

from dataclasses import dataclass

@dataclass
class Foo:
    x: int = 0
class Foo:
    def __init__(self, x: int = 0) -> None:
        self.x = x

しかし、python 3.8.6と3.9.0で試してみた限り、@dataclassを使って定義したデフォルト値はクラス変数として扱われてしまった。

from dataclasses import dataclass

@dataclass
class Foo:
    x: int = 0

    @classmethod
    def print_x(cls):
        print(cls.x)

Foo.print_x()  #=> 0

クラス変数とインスタンス変数を取り違えれば問題が起こることはこの記事が詳しい。

3
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?