LoginSignup
5
7

More than 3 years have passed since last update.

Pythonの関数のデフォルト値は後から変更できる

Posted at

前書き

このように、ミュータブルなデフォルト値を持っている関数pileを定義したとする。

>>> def pile(num, lst=[]):
...     lst.append(num)
...     return lst
...
>>>

このデフォルト値は、当該関数オブジェクト自体が保持している。

>>> pile(1)
[1]
>>> pile(2)
[1, 2]
>>> pile(42)
[1, 2, 42]

他言語に慣れている人から見れば随分奇怪な挙動であるが、これが仕様なのだから致し方ない。
公式リファレンスに至っては、『キャッシュに使えば?』なんて提案をしているほどである。1

デフォルト値の確認

ユーザ定義関数の特殊属性を参照すれば、デフォルト値を確認することができる。

属性 意味
__defaults__ デフォルト値を持つ引数に対するデフォルト値が収められたタプルで、
デフォルト値を持つ引数がない場合には None になります
__kwdefaults__ キーワード専用パラメータのデフォルト値を含む辞書です。

引用元: Python 言語リファレンス » 標準型の階層 » 呼び出し可能型 (一部抜粋)

>>> def func(arg1, arg2=10, *, kwarg1=20, kwarg2=30):
...     pass
...
>>> func.__defaults__
(10,)
>>> func.__kwdefaults__
{'kwarg1': 20, 'kwarg2': 30}

デフォルト値は変更可能である

次のような操作が可能である。

>>> def pile(num, lst=[]):
...     lst.append(num)
...     return lst
...
>>>
>>> pile(1)
[1]
>>>
>>> pile.__defaults__[0].append(42)
>>> pile(2)
[1, 42, 2]

特殊属性__defaults__はタプルであるので、直下の要素を置き換えることはできない。
しかし、丸ごとごっそり書き直す分には何の問題もない。2

>>> pile.__defaults__
([1, 42, 2],)
>>>
>>> pile.__defaults__ = [],
>>> pile(3)
[3]

元々デフォルト値が無い仮引数に影響することすら可能である。

>>> pile.__defaults__ = -1, []
>>>
>>> pile()
[-1]
>>> pile()
[-1, -1]
>>> pile()
[-1, -1, -1]

デフォルト値の割り振られ方

過少あるいは過剰なデフォルト値を与えた場合、それらの割り振られ方は独特である。

>>> def func(arg1, arg2, arg3):
...     print(arg1, arg2, arg3)
...
>>> func.__defaults__ = 1, 2
>>> func()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: func() missing 1 required positional argument: 'arg1'
>>>
>>> func.__defaults__ = 1, 2, 3
>>> func()
1 2 3
>>>
>>> func.__defaults__ = 1, 2, 3, 4
>>> func()
2 3 4
>>>
>>> func.__defaults__ = 1, 2, 3, 4, 5
>>> func()
3 4 5

使いどころ

特に思い浮かばない。
多用する引数のデフォルト値を決めたい場合は、ラッパー関数を書けば良いわけで。


  1. 『ミュータブルなオブジェクトを指定するな』という、真っ当なアドバイスもしている。 

  2. 書き込み可能であるとドキュメントに明記されている。 

5
7
0

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
5
7