結論から言うと
渡せません。
回避策として、以下のように書くことになります。
- デフォルト引数に
None等を与えたのち - メソッド内で引数が
Noneかどうかを判定し、Noneならインスタンス変数を引数に代入する
やりたいこと
Pythonのインスタンスメソッドのパラメータのうち、「指定しなければインスタンス変数を使う」ような挙動をさせたい。
最初に考えて書いたのが以下のコード。
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 である時にだけ、関数の内部で新しいリスト/辞書/その他をつくるようにしてください。
これに則って書くとこうなります。
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
追記 :
- 公開タイミングでいきなり「クラスメソッドとインスタンスメソッド間違える」という痛恨のミスをご指摘いただき修正しました。