web-dev-qa-db-ja.com

PyCharmの可変デフォルト引数に関する警告

私はPyCharm(Python 3)を使用して、attachment={}を引数として辞書を受け入れるPython関数を記述しています。

def put_object(self, parent_object, connection_name, **data):
    ...

def put_wall_post(self, message, attachment={}, profile_id="me"):
    return self.put_object(profile_id, "feed", message=message, **attachment)

IDEでは、attachment={}は黄色で表示されます。マウスをその上に移動すると、警告が表示されます。

デフォルトの引数値は可変です

この検査は、リストまたは辞書としての可変値が引数のデフォルト値で検出されたことを検出します。

デフォルトの引数値は、関数定義時に1回だけ評価されます。つまり、引数のデフォルト値を変更すると、関数の以降のすべての呼び出しに影響します。

これはどういう意味ですか、どうすれば解決できますか?

30
bin

「可変デフォルト引数」を変更したり、変更可能な場所に渡したりしない場合は、「修正」するものがないため、メッセージを無視してください。

あなたの場合、only「mutable default argument」をアンパック(暗黙のコピーを行います)-安全です。

「その警告メッセージを削除する」場合は、Noneをデフォルトとして使用し、Noneのときに{}に設定できます。

def put_wall_post(self,message,attachment=None,profile_id="me"):
    if attachment is None:
        attachment = {}

    return self.put_object(profile_id,"feed",message = message,**attachment)

「それが何を意味するか」を説明するために:Pythonの一部の型は不変(intstr、...)であり、他の型は可変です(dictsetlist、...)。不変オブジェクトを変更したい場合、別のオブジェクトが作成されます-しかし、可変オブジェクトを変更した場合、オブジェクトは同じままですが、内容が変更されます。

トリッキーな部分は、クラス変数とデフォルト引数が関数のロード時に(そして一度だけ)作成されることです。つまり、「可変デフォルト引数」または「可変クラス変数」への変更は永続的です。

def func(key, value, a={}):
    a[key] = value
    return a

>>> print(func('a', 10))  # that's expected
{'a': 10}
>>> print(func('b', 20))  # that could be unexpected
{'b': 20, 'a': 10}

PyCharmはおそらく誤って間違ってしまうため、この警告を表示します(たとえば、 「Least Astonishment」とMutable Default Argument およびリンクされているすべての質問を参照)。ただし、意図的にそれを行った場合( 可変関数の引数のデフォルト値に適していますか? )警告は迷惑になる可能性があります。

35
MSeifert

可変のデフォルト引数をNoneに置き換えることができます。次に、関数の内部を確認し、デフォルトを割り当てます。

_def put_wall_post(self, message, attachment=None, profile_id="me"):
    attachment = attachment if attachment else {}

    return self.put_object(profile_id, "feed", message=message, **attachment)
_

これは、NoneFalseに評価されるため、空の辞書を割り当てるために機能します。

一般に、他の値もNoneに評価される可能性があるため、Falseを明示的にチェックすることができます。 _0_、_''_、set()、_[]_などはすべて_False-y_です。デフォルトが_0_でなく、たとえば_5_である場合、有効なパラメーターとして渡される_0_を踏みたくありません:

_def function(param=None):
    param = 5 if param is None else param
_
4
Peter Wood