Pythonをいじくり回している人は誰でも、次の問題で噛まれ(または引き裂かれ)ています。
def foo(a=[]):
a.append(5)
return a
Python初心者は、この関数が常に1つの要素のみのリストを返すことを期待します[5]
。結果は非常に異なり、非常に驚くべきものです(初心者にとって)。
>>> foo()
[5]
>>> foo()
[5, 5]
>>> foo()
[5, 5, 5]
>>> foo()
[5, 5, 5, 5]
>>> foo()
私のマネージャーはかつてこの機能に初めて遭遇し、それを言語の「劇的な設計上の欠陥」と呼んでいました。私はその振る舞いには根本的な説明があったと答えました、そしてあなたがその内部を理解していなければ、それは確かに非常に不可解で予想外です。しかし、私は次の質問に(自分自身で)答えることができませんでした。関数の実行時にではなく、関数の定義時にデフォルト引数をバインドする理由は何ですか?経験豊富な振る舞いが実際に使用されているとは思えません(実際にバグを増殖させることなく、Cで静的変数を使用したのは誰ですか?)
編集:
Baczekは興味深い例を作りました。あなたのほとんどのコメント、特にウタールのコメントとともに、私はさらに詳しく説明しました:
>>> def a():
... print("a executed")
... return []
...
>>>
>>> def b(x=a()):
... x.append(5)
... print(x)
...
a executed
>>> b()
[5]
>>> b()
[5, 5]
私には、設計の決定は、パラメーターのスコープをどこに置くかとの関係にあったようです:関数の内部か、それと「一緒に」ですか?
関数内でバインディングを行うx
と、定義されていない関数が呼び出されたときに、指定されたデフォルトに効果的にバインドされます。これは、重大な欠陥を示すものdef
です。関数オブジェクト)は定義時に発生し、一部(デフォルトパラメータの割り当て)は関数の呼び出し時に発生します。
実際の動作はより一貫性があります。その行のすべては、その行が実行されると評価されます。つまり、関数定義で評価されます。
[5]
。」私は、Pythonの初心者だし、明らかにので、私は、このことを期待していないfoo([1])
が返されます[1, 5]
、ではありません[5]
。あなたが言うつもりだったことは、初心者はパラメータなしで呼び出された関数が常に戻ることを期待するということ[5]
です。