ホームページ  >  記事  >  バックエンド開発  >  Python関数のパラメータのデフォルト値が可変オブジェクトの場合は注意が必要

Python関数のパラメータのデフォルト値が可変オブジェクトの場合は注意が必要

WBOY
WBOY転載
2023-04-22 13:37:071218ブラウズ

フィボナッチ関数の再帰を高速化するために、変数オブジェクトが Python 関数のパラメータのデフォルト値に渡されているのを見ました。コードは次のとおりです:

def fib(n, cache={0: 0, 1: 1}):
if n not in cache:
cache[n] = fib(n - 1) + fib(n - 2)
return cache[n]

おかしくないですか?これができるということですか? 速度は本当に非常に速く、実行結果は次のとおりです:

小心此坑:Python 函数参数的默认值是可变对象

## ただし、これは行わないことをお勧めします。

小心此坑:Python 函数参数的默认值是可变对象

これは、すべてがオブジェクトであり、Python 関数もオブジェクトであるためです。パラメータのデフォルト値は、次の属性です。オブジェクト。パラメータのデフォルト値はコンパイル段階ですでに関数にバインドされています。変数オブジェクトの場合、Python 関数パラメータのデフォルト値は保存され、すべての呼び出し元で共有されます。つまり、関数パラメータのデフォルト値は、List や Dict などの変数オブジェクトであり、呼び出し元 A がそれを変更しました。その後、呼び出し元 B は、呼び出し時に A の変更結果を見ることになります。このようなモードでは、上記の fib アルゴリズムなど、予期しない結果が生じることがよくあります。しかし、それらのほとんどはバグです。

次の簡単なコードを見てみましょう:

def func(n, li = []):
for i in range(n):
li.append(i)
print(l)

func(2) # [0,1]
func(3,l=[1,2]) # [1,2,0,1,2]
func(2) # [0,1]

まず、このコードの出力を見積もることができます。コメント内の出力と同じであれば、間違っています。正しい結果は次のとおりです:

[0, 1]
[1, 2, 0, 1, 2]
[0, 1, 0, 1]

最後の func(2) がなぜこのようになっているか疑問に思うかもしれませんが、心配しないで、 print(id(li)) をデバッグしましょう:

def func(n, li = []):
print(id(li))
for i in range(n):
li.append(i)
print(li)

func(2)
func(3,li=[1,2])
func(2)

結果は次のとおりです。

140670243756736
[0, 1]
140670265684928
[1, 2, 0, 1, 2]
140670243756736
[0, 1, 0, 1]

最初の func(2) と 2 番目の func(2) の ID が同じであることに気づきましたか。これは、デフォルト値である同じ li を使用していることを示しています。これは変更可能なオブジェクトのロジックであり、すべての呼び出し元によって共有されます。

Python がこのように設計されている理由を詳しく知りたい場合は、http://cenalulu.github.io/python/default-mutable-arguments/

回避方法を参照してください。それ?

最善の方法は、可変オブジェクトを関数のデフォルト値として使用しないことです。この方法で使用する必要がある場合の解決策は次のとおりです:

def generate_new_list_with(my_list=None, element=None):
if my_list is None:
my_list = []
my_list.append(element)
return my_list

このように、my_list のデフォルト値が常に [] である場合。

最後に

#fib 関数の実装に感動するかもしれませんが、そのような使用法は非常に危険であり、独自のコードでは使用できないことに注意してください。

以上がPython関数のパラメータのデフォルト値が可変オブジェクトの場合は注意が必要の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事は51cto.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。