web-dev-qa-db-fra.com

Avertissement concernant l'argument par défaut modifiable dans PyCharm

J'utilise PyCharm (Python 3) pour écrire une fonction Python qui accepte un dictionnaire comme argument avec attachment={}.

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)

Dans l'EDI, attachment={} est de couleur jaune. Déplacer la souris dessus affiche un avertissement.

La valeur des arguments par défaut est modifiable

Cette inspection détecte lorsqu'une valeur modifiable comme liste ou dictionnaire est détectée dans une valeur par défaut pour un argument.

Les valeurs d'argument par défaut sont évaluées une seule fois au moment de la définition de la fonction, ce qui signifie que la modification de la valeur par défaut de l'argument affectera tous les appels suivants de la fonction.

Qu'est-ce que cela signifie et comment puis-je le résoudre?

30
bin

Si vous ne modifiez pas "l'argument par défaut mutable" ou ne le passez pas où il pourrait être modifié, ignorez simplement le message, car il n'y a rien à "corriger".

Dans votre cas, vous seulement décompressez (qui fait une copie implicite) l '"argument par défaut mutable" - donc vous êtes en sécurité.

Si vous souhaitez "supprimer ce message d'avertissement", vous pouvez utiliser None par défaut et le définir sur {} quand c'est 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)

Juste pour expliquer le "ce que cela signifie": certains types dans Python sont immuables (int, str, ...) d'autres sont mutables (comme dict, set, list, ...). Si vous voulez changer des objets immuables un autre objet est créé - mais si vous changez des objets mutables, l'objet reste le même mais c'est le contenu est modifié.

La partie délicate est que les variables de classe et les arguments par défaut sont créés lorsque la fonction est chargée (et une seule fois), ce qui signifie que toutes les modifications apportées à un "argument par défaut mutable" ou à une "variable de classe mutable" sont permanentes:

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 affiche probablement cet avertissement car il est facile de se tromper par accident (voir par exemple "Le moindre étonnement" et l'argument par défaut Mutable et toutes les questions liées). Cependant, si vous l'avez fait exprès ( bonnes utilisations pour les valeurs par défaut des arguments de fonction mutables? ) l'avertissement pourrait être ennuyeux.

35
MSeifert

Vous pouvez remplacer les arguments par défaut modifiables par None. Vérifiez ensuite à l'intérieur de la fonction et attribuez la valeur par défaut:

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)

Cela fonctionne car None est évalué à False et nous attribuons donc un dictionnaire vide.

En général, vous souhaiterez peut-être vérifier explicitement None car d'autres valeurs peuvent également être évaluées à False, par exemple 0, '', set(), [], Etc., sont tous False-y. Si votre valeur par défaut n'est pas 0 Et est par exemple 5, Alors vous ne voudriez pas piétiner que 0 Est passé comme paramètre valide:

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