47

私はPythonの初心者で、「Pythonチュートリアル」を読んでいます。関数があるかどうかは次のとおりです。

def f(a, L=[]):
     L.append(a)
     return L
print f(1)
print f(2)
print f(3)

これは印刷されます

[1]
[1, 2]
[1, 2, 3]

デフォルト値は 1 回だけ評価され、list は変更可能なオブジェクトであるためです。私はそれを理解することができます。

後続の呼び出し間でデフォルトを共有したくない場合は、次のことができます。

def f(a, L=None):
   if L is None:           #line  2
       L = []            
   L.append(a)
   return L
print f(1)            
print f(2)
print f(3)

これは次のように出力されます。

[1]
[2]
[3]

しかし、なぜですか?これを説明する方法。デフォルト値は評価のみであることがわかってonceおり、f(2) を呼び出すと、L は None ではなく、(2if行目で) true にならないため、L.append(a) == [1, 2] になります。なんらかの理由でデフォルト値が再度評価されると推測できますが、「何らかの理由」とは何か、Pythonインタープリターが見るからですif L is None: L = []

4

5 に答える 5

36

Python はパラメーターを関数に値で渡します。したがって、オブジェクトの場合、渡される値はobject への参照であり、オブジェクトの新しいコピーではありません。

それは、公式ドキュメントの次の部分とともに、私がそれをよりよく理解するのに役立ちました(私の強調):

デフォルトのパラメーター値は、関数定義が実行されるときに評価されます [...]。これは、関数が定義されるときに式が一度評価され、同じ「事前に計算された」値が各呼び出しに使用されることを意味します。これは、既定のパラメーターがリストや辞書などの変更可能なオブジェクトである場合に特に重要です。関数がオブジェクトを変更する場合 (たとえば、項目をリストに追加することによって)、既定値は事実上変更されます。[...]これを回避する方法は、Noneをデフォルトとして使用し、関数の本体で明示的にテストすることです[...]

すべてを一緒に入れて:

パラメータのデフォルトを変更可能なオブジェクト ( など[]) に定義すると、「事前に計算された」値がそのオブジェクトへの参照になるため、関数への各呼び出しは常に同じオブジェクトを参照し、後で変更することができます。関数の複数の呼び出しにわたって。

ただし、Noneは不変の組み込み型であるため、デフォルトの の「事前に計算された」値Noneは単純です。Noneそのため、関数を呼び出すたびにパラメーターが になります。

うまくいけば、それは役に立ちます!私も最初は混乱していたので、チュートリアルの言葉遣いがもっと良かったと思います。

于 2015-11-06T18:25:05.313 に答える
19

「デフォルト値は一度だけ評価される」ということは、デフォルトを持つパラメータが関数の呼び出し間でその値を保持するという意味ではありません。これは、指定した式 ( のNone部分def f(a, L=None)) が 1 回評価され、その結果のオブジェクトが非表示の場所に格納され、呼び出し時にそのパラメーターの値が指定されていない場合に再利用されることを意味します。パラメーターは、呼び出しごとに値 (デフォルトかどうか) にリセットされます。

于 2012-10-26T13:03:25.973 に答える
3

2 番目の例では、 variable がありますL。最初Lに参照しNoneます。呼び出しごとに新しい空のリストに再ポイントし、その新しいリストを変更します覚えておいてくださいL = []と同じですL = list()

ただし、最初の例では、関数宣言時に L が新しいリストに一度設定されます。L は[]、関数の呼び出しごとにリセットされません。したがって、常に同じリストを変更しています。

于 2012-10-26T12:59:13.797 に答える
2

何が起こるかは次のとおりです。

Python関数が呼び出されると、それが定義された環境で評価され、2番目の部分は質問に答える目的で2番目の部分(しゃれは意図されていません)が呼び出された環境では評価されません。

デフォルトの引数は、関数の定義時に一度だけ評価されます。これにより、クロージャが作成されます。クロージャーは、関数コード + 関数が定義された環境と考えてください。

したがって、この場合、関数が定義されたときにLに割り当てられ[]、関数への後続のすべての呼び出しでこの の値が使用されますL

チュートリアルには次のことも記載されています。

デフォルト値は、定義スコープ内の関数定義の時点で評価されます(定義スコープは、関数コードとともにクロージャの一部です)。

http://docs.python.org/2/tutorial/controlflow.html#default-argument-values

于 2013-12-31T20:00:07.923 に答える