Pixel Pedals of Tomakomai

北海道苫小牧市出身の初老の日常

間違いやすいPythonのクラス変数とインスタンス変数(2)

Pythonネタを書いたら、狙っていた通りckuwataさんが補足をくれたので追エントリしときます*1。ありがとうございます!

要するにこれは「class の直下で変数宣言をしたい」「でも普通にそれをやるとクラス変数になってしまう」という問題なわけだな。こういう場合にどうするかというと、プロパティを使うのが多分スマートだろう。

Diary?

なるほど、確かにフィールドを直接触るよりプロパティを使うのが自然ですね。ただ、なんでもかんでもプロパティにするのかと思いきや、

ちなみに俺の方針としては、

  • 外部仕様として公開するのならプロパティ
  • そうでなければ __init__ 内部に列挙

というのがバランスのとれたやり方かなと思ってる。

Diary?

とのこと。確かに、プロパティの記法は長いのでプライベート値まで全部作ってると泣けますね。


ちなみに、シャドーイングもかなり心惹かれる手法ですが*2、デコレータマニアとしてはドキュメントに出ていた、

class C(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

2. Built-in Functions

が好きです。バージョン依存あるかもしれないですが。

で、クラス変数として定義すると結局何がまずいのさ?

順番おかしいですが、最後にクラス変数として定義しちゃ駄目な例をあげときます*3。listやdictはミュータブルなので、以下のようなコードは危険です。

>>> class Hoge(object):
...     foo = []
... 
>>> hoge1 = Hoge()
>>> hoge1.foo.append("I'm hoge1.")
>>> hoge2 = Hoge()
>>> hoge2.foo
["I'm hoge1."]

逆にイミュータブルな値であれば、動きとしての問題はおきないし、デフォルト値を使い回すことでメモリの節約も狙えます。

*1:追記にしたかったんだけど長くなった

*2:シャドーイングって言葉は初めて知った

*3:普通にクラス変数をインスタンス変数としてる例も見かけたので、主張をはっきりするのに念のため。