Parfois, il semble naturel d'avoir un paramètre par défaut qui est une liste vide. Pourtant, Python donne un comportement inattendu dans ces situations .
Si par exemple, j'ai une fonction:
def my_func(working_list = []):
working_list.append("a")
print(working_list)
La première fois qu'elle est appelée, la valeur par défaut fonctionnera, mais les appels suivants mettront à jour la liste existante (avec un "a" à chaque appel) et imprimera la version mise à jour.
Alors, quelle est la manière pythonique d'obtenir le comportement que je désire (une nouvelle liste à chaque appel)?
python
python-3.x
John Mulder
la source
la source
Réponses:
Les documents indiquent que vous devez utiliser
None
par défaut et le tester explicitement dans le corps de la fonction.la source
f()
une liste, vous devez appelerf(*l)
ce qui est grossier. Pire encore, la mise en œuvremate(['larch', 'finch', 'robin'], ['bumble', 'honey', 'queen'])
serait SUCK w / varargs. Beaucoup mieux si c'estdef mate(birds=[], bees=[]):
.Les réponses existantes ont déjà fourni les solutions directes demandées. Cependant, comme il s'agit d'un piège très courant pour les nouveaux programmeurs Python, il vaut la peine d'ajouter l'explication pourquoi python se comporte de cette façon, ce qui est bien résumé dans " le Guide des auto-stoppeurs de Python " comme " Arguments mutables par défaut ": http: // docs .python-guide.org / fr / dernier / écriture / gotchas /
Quote: " Les arguments par défaut de Python sont évalués une fois lorsque la fonction est définie, pas à chaque fois que la fonction est appelée (comme c'est le cas, par exemple, Ruby). Cela signifie que si vous utilisez un argument par défaut mutable et que vous le muter, vous aurez et aurez muté cet objet pour tous les futurs appels à la fonction également "
Exemple de code pour l'implémenter:
la source
Ce n'est pas important dans ce cas, mais vous pouvez utiliser l'identité d'objet pour tester None:
Vous pouvez également profiter de la façon dont l'opérateur booléen ou est défini en python:
Bien que cela se comporte de manière inattendue si l'appelant vous donne une liste vide (qui compte comme fausse) comme working_list et s'attend à ce que votre fonction modifie la liste qu'il lui a donnée.
la source
Si l'intention de la fonction est de modifier le paramètre passé en tant que
working_list
, consultez la réponse de HenryR (= Aucun, vérifiez Aucun à l'intérieur).Mais si vous n'avez pas l'intention de muter l'argument, utilisez-le simplement comme point de départ d'une liste, vous pouvez simplement le copier:
(ou dans ce cas simple,
print starting_list + ["a"]
mais je suppose que ce n'était qu'un exemple de jouet)En général, muter vos arguments est un mauvais style en Python. Les seules fonctions dont on attend totalement la mutation d'un objet sont les méthodes de l'objet. Il est encore plus rare de faire muter un argument optionnel - un effet secondaire qui ne se produit que dans certains appels est-il vraiment la meilleure interface?
Si vous le faites à partir de l'habitude C des "arguments de sortie", c'est complètement inutile - vous pouvez toujours renvoyer plusieurs valeurs sous forme de tuple.
Si vous faites cela pour créer efficacement une longue liste de résultats sans créer de listes intermédiaires, envisagez de l'écrire en tant que générateur et de l'utiliser
result_list.extend(myFunc())
lorsque vous l'appelez. De cette façon, vos conventions d'appel restent très propres.Un modèle où la mutation d'un argument optionnel est fréquemment effectuée est un arg "mémo" caché dans les fonctions récursives:
la source
Je suis peut-être hors sujet, mais rappelez-vous que si vous voulez juste passer un nombre variable d'arguments, la manière pythonique est de passer un tuple
*args
ou un dictionnaire**kargs
. Ceux-ci sont facultatifs et sont meilleurs que la syntaxemyFunc([1, 2, 3])
.Si vous voulez passer un tuple:
Si vous voulez passer un dictionnaire:
la source
Des réponses bonnes et correctes ont déjà été fournies. Je voulais juste donner une autre syntaxe pour écrire ce que vous voulez faire, ce que je trouve plus beau lorsque vous voulez par exemple créer une classe avec des listes vides par défaut:
Cet extrait de code utilise la syntaxe de l'opérateur if else. Je l'aime particulièrement parce que c'est un joli petit one-liner sans deux-points, etc. impliqué et il se lit presque comme une phrase anglaise normale. :)
Dans votre cas, vous pourriez écrire
la source
J'ai suivi la classe d'extension UCSC
Python for programmer
Ce qui est vrai pour: def Fn (data = []):
Répondre:
la source