Help us understand the problem. What is going on with this article?

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

前書き

このように、ミュータブルなデフォルト値を持っている関数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. 書き込み可能であるとドキュメントに明記されている。 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした