Python 3 エンジニア認定基礎試験 無料問題 9 / 10 ・ 分野9: 9章 クラス
次のコードを実行したときの表示はどれか。 class C: items = [] tag = 'x' a = C() b = C() a.items.append(1) a.tag = 'y' print(len(b.items), b.tag)
- 0 y
- 1 x
- 0 x
- 1 y
正解と解説を見る
正解: B
正解の理由
クラス変数は、そのクラスのすべてのインスタンスによって共有される。items = [] で作られたリストは1つしかなく、a.items.append(1) はその共有のリストを変更するので、b.items の長さも 1 になる。一方 a.tag = 'y' はインスタンス a に新しいデータ属性 tag を作る代入で、クラスの tag は変えない。b には tag という属性が無いので、属性の検索はクラスに進み、'x' が見つかる。表示は 1 x である。
違う選択肢
「0 x」… クラス変数のリストが、インスタンスを作るたびに別々に用意されると読んだ場合の結果。クラス定義の中で作ったリストは1つだけで、すべてのインスタンスに共有される。a.items.append(1) はその1つのリストを変更するので、b.items の長さも 1 になる。
「1 y」… a.tag = 'y' がクラス変数 tag を書き換えると読んだ場合の結果。インスタンスへの代入は、そのインスタンスの属性を作るだけで、クラスの tag は 'x' のまま残る。b にはインスタンスの tag が無いので、クラスの 'x' が見える。
「0 y」… リストがインスタンスごとに別だと読み、さらにインスタンスへの代入がクラスの値を変えると読んだ場合の結果。実際はその逆で、リストは共有され、a.tag への代入は b に影響しない。
正しい設計
チュートリアルは、Dog クラスの tricks リストをクラス変数にした例を「誤った使い方」として示し、__init__ の中で self.tricks = [] としてインスタンスごとに新しいリストを作るよう勧めている。インスタンスとクラスの両方に同じ名前の属性があるときは、インスタンスのほうが優先される。