多くの回答には完全な情報の一部が含まれているので、すべてを私のお気に入りのパターンと一緒にまとめたいと思います。
デフォルト値はmutable
タイプです
デフォルト値が可変オブジェクトの場合、幸運です。関数が定義されたときにPythonのデフォルト引数が1回評価されるという事実を利用できます(これについては、前のセクションの回答の最後にあります)。
これはis
、関数またはメソッドとして次の例のように、を使用してデフォルトの可変値を簡単に比較して、引数として渡されたか、デフォルトで残されたかを確認できることを意味します。
def f(value={}):
if value is f.__defaults__[0]:
print('default')
else:
print('passed in the call')
そして
class A:
def f(self, value={}):
if value is self.f.__defaults__[0]:
print('default')
else:
print('passed in the call')
不変のデフォルト引数
さて、デフォルトが値であると予想されるimmutable
場合(そして文字列でさえ不変であることを忘れないでください!)、トリックをそのまま利用することはできませんが、まだできることがあり、可変性を利用しているため、少しエレガントではありませんタイプ; 基本的に、関数のシグネチャに変更可能な「偽の」デフォルト値を設定し、関数の本体に目的の「実際の」デフォルト値を設定します。
def f(value={}):
"""
my function
:param value: value for my function; default is 1
"""
if value is f.__defaults__[0]:
print('default')
value = 1
else:
print('passed in the call')
print(value)
実際のデフォルトがNone
である場合は特におかしいと感じますが、None
不変なので...関数のデフォルトパラメータとして明示的に可変を使用し、コードで[なし]に切り替える必要があります。
Default
不変のデフォルトにクラスを使用する
または、@ czの提案と同様に、Pythonドキュメントでは不十分な場合:-)、間にオブジェクトを追加して、APIをより明示的にすることができます(ドキュメントを読まなくても)。used_proxy_ Defaultクラスインスタンスは変更可能であり、使用する実際のデフォルト値が含まれます。
class Default:
def __repr__(self):
return "Default Value: {} ({})".format(self.value, type(self.value))
def __init__(self, value):
self.value = value
def f(default=Default(1)):
if default is f.__defaults__[0]:
print('default')
print(default)
default = default.value
else:
print('passed in the call')
print("argument is: {}".format(default))
今:
>>> f()
default
Default Value: 1 (<class 'int'>)
argument is: 1
>>> f(2)
passed in the call
argument is: 2
上記は、に対してもうまく機能しDefault(None)
ます。
その他のパターン
明らかに、上記のパターンは、それらがprint
どのように機能するかを示すためだけに存在するため、本来よりも醜く見えます。そうでなければ、私はそれらが簡潔で十分に再現可能であると思います。
あなたは追加するデコレータを書くことができ__call__
、より合理化された方法で@dmgによって提案されたパターンが、これは関数定義そのものに奇妙なトリックを使用して、まだリージュ意志を-あなたはアウト分割する必要があるだろうvalue
し、value_default
あなたのコードの必要性は、それらを区別する場合には、そう私はあまり利点が見当たらず、例を書きません:-)
Pythonのデフォルト値としての可変型
#1 pythonの落とし穴についてもう少し!、上記のあなた自身の喜びのために虐待されました。次の手順を実行すると、定義時の評価によって何が起こるかを確認できます。
def testme(default=[]):
print(id(default))
何度でも実行できtestme()
、常に同じデフォルトインスタンスへの参照が表示されます(したがって、基本的にデフォルトは不変です:-))。
Pythonであることを覚えておいてくださいのみ3可変ビルトインタイプ:set
、list
、dict
; 他のすべて-文字列さえ!-不変です。