15
11

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 5 years have passed since last update.

Pythonのインスタンスメソッドのデフォルト引数に、インスタンス変数を渡したい

Last updated at Posted at 2019-03-21

結論から言うと

渡せません。
回避策として、以下のように書くことになります。

  • デフォルト引数にNone等を与えたのち
  • メソッド内で引数がNoneかどうかを判定し、Noneならインスタンス変数を引数に代入する

やりたいこと

Pythonのインスタンスメソッドのパラメータのうち、「指定しなければインスタンス変数を使う」ような挙動をさせたい。
最初に考えて書いたのが以下のコード。

instancemethod_fail.py
class MyClass:
    def __init__(self):
        self.var1 = "instance var"

    def some_method(self, param=self.var1):
        print(param)

MyClass().some_method()

これを実行しようとするとコケます。

$ python instancemethod_fail.py 
Traceback (most recent call last):
  File "instancemethod_fail.py", line 1, in <module>
    class MyClass:
  File "instancemethod_fail.py", line 5, in MyClass
    def some_method(self, param = self.var1):
NameError: name 'self' is not defined

なぜうまく行かないのか

Pythonのメソッドのデフォルト引数はクラスを定義したタイミングで評価されるからです。

参考 : 4. その他の制御フローツール — Python 3.7.3rc1 ドキュメント

重要な警告: デフォルト値は 1 度だけしか評価されません。デフォルト値がリストや辞書のような変更可能なオブジェクトの時にはその影響がでます。

Python初学者が陥りやすい定番のハマりどころとして、Pythonの公式FAQにも以下のように記載されています。

プログラミング FAQ — Python 3.7.3rc1 ドキュメント
「なぜオブジェクト間でデフォルト値が共有されるのですか?」項より

関数の呼び出しによって、デフォルトの値に対する新しいオブジェクトが作られるのだと予想しがちです。実はそうなりません。デフォルト値は、関数が定義されたときに一度だけ生成されます。この例の辞書のように、そのオブジェクトが変更されたとき、その後の関数の呼び出しは変更後のオブジェクトを参照します。

「デフォルト値は関数定義のタイミングで1度だけ評価される」ため、その時点で定義されていないselfを参照できなかったということですね。

どう解決するのか

上記の続きとして、以下のように記載されています。

定義の時に、数、文字列、タプル、None など、イミュータブルなオブジェクトを使うと変更される危険がありません。辞書、リスト、クラスインスタンスなどのミュータブルなオブジェクトは混乱のもとです。

この性質から、ミュータブルなオブジェクトをデフォルト値として使わないプログラミング手法がいいです。代わりに、None をデフォルト値に使い、そのパラメタが None である時にだけ、関数の内部で新しいリスト/辞書/その他をつくるようにしてください。

これに則って書くとこうなります。

instancemethod.py
class MyClass:
    def __init__(self):
        self.var1 = "instance var"

    def some_method(self, param=None):
        if param is None:
            param = self.var1
        print(param)

MyClass().some_method()

こうするとちゃんと動きます。

$ python instancemethod.py 
instance var

追記 :

  • 公開タイミングでいきなり「クラスメソッドとインスタンスメソッド間違える」という痛恨のミスをご指摘いただき修正しました。
15
11
4

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
15
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?