Python3 コンストラクタ__init__ の初期化の値について
Python3 で Wikipedia のデータを解析するために、
class Entry: def __init__(self, title, redirect_from=[], document=None, link_from=[], link_to=None): self.title = title self.redirect_from = redirect_from self.document = document self.link_from = link_from self.link_to = link_to
というクラスを作ってデータを入力していたのですが、何故か全インスタンスの redirect_from のデータを見ると同じ内容だったので、もしかして同じものが参照されているのかと思って調べてみました。 Python3 のオブジェクト x は id(x) を使って調べることが出来ます。
>>> class A: ... def __init__(self, a=[]): ... self.a = a ... >>> a = A() >>> b = A() >>> id(a.a) == id(b.b) True
どうやらコンストラクタでデフォルト引数にオブジェクトを渡すと、共通した値を使ってしまうようですね。
結局対策として簡単に思いつくのは
class Entry: def __init__(self, title, redirect_from=None, document=None, link_from=None, link_to=None): self.title = title if redirect_from == None: self.redirect_from = [] else: self.redirect_from = redirect_from self.document = document if link_from == None: self.link_from = [] else: self.link_from = link_from self.link_to = link_to
というように、デフォルト引数に None を指定しておき、引数が None だったら [] を渡すというようにします。これだと None を値に持たせることが出来ませんが、デフォルトを空リストにしたい場合ですから殆どの場面で大丈夫だと思います。あるいはどうしても None を値に持たせたくなればインスタンスを作ったあとに None を代入します。