En Python, que signifie dict.pop (a, b)?

92
class a(object):
    data={'a':'aaa','b':'bbb','c':'ccc'}
    def pop(self, key, *args):
            return self.data.pop(key, *args)#what is this mean.

b=a()
print b.pop('a',{'b':'bbb'})
print b.data

self.data.pop(key, *args) ← ------ pourquoi y a-t-il un deuxième argument?

zjm1126
la source
8
Ou si vous êtes vraiment paresseux help(b.data.pop)dans le REPL.
Michael Mior

Réponses:

120

La popméthode des dicts (comme self.data, c'est-à-dire {'a':'aaa','b':'bbb','c':'ccc'}ici) prend deux arguments - voir la documentation

Le deuxième argument,, defaultest ce qui poprevient si le premier argument key,, est absent. (Si vous appelez popavec un seul argument key,, cela déclenche une exception si cette clé est absente).

Dans votre exemple, print b.pop('a',{'b':'bbb'})ce n'est pas pertinent car il 'a' s'agit d' une clé b.data. Mais si vous répétez cette ligne ...:

b=a()
print b.pop('a',{'b':'bbb'})
print b.pop('a',{'b':'bbb'})
print b.data

vous verrez que cela fait une différence: le premier popsupprime la 'a'clé, donc dans le second popl' defaultargument est effectivement retourné (car il 'a'est maintenant absent de b.data).

Alex Martelli
la source
3
Juste un petit commentaire qui, à mon avis, est important dans certaines situations où l'utilisateur a besoin d' popun élément dictmais conserve la valeur de l'élément sauté. Ainsi, dict.pop(key)supprime le keyavec le associé valuemais renvoie également le valuede keyqui vient d'être supprimé. Je l'ai trouvé utile ...
flamenco
@flamenco c'est ce à quoi j'attends pop()- un comportement commun dans plus de langages comme JavaScript, PHP, Java, bien que tous les langages ne le fassent pas - par exemple C ++.
jave.web
27

Tant de questions ici. J'en vois au moins deux, peut-être trois:

  • Que fait pop (a, b)? / Pourquoi y a-t-il un deuxième argument?
  • À quoi *argssert-il?

La première question trouve une réponse triviale dans la référence de la bibliothèque standard Python :

pop (clé [, par défaut])

Si la clé est dans le dictionnaire, supprimez-la et renvoyez sa valeur, sinon renvoyez la valeur par défaut. Si la valeur par défaut n'est pas indiquée et que la clé n'est pas dans le dictionnaire, une KeyError est déclenchée.


La deuxième question est traitée dans la référence du langage Python :

Si la forme «* identifiant» est présente, elle est initialisée à un tuple recevant tous les paramètres de position en excès, par défaut au tuple vide. Si la forme «** identifiant» est présente, elle est initialisée à un nouveau dictionnaire recevant tout argument de mot-clé en excès, par défaut à un nouveau dictionnaire vide.

En d'autres termes, la popfonction prend au moins deux arguments. Les deux premiers reçoivent les noms selfet key; et le reste est placé dans un tuple appelé args.

Ce qui se passe sur la ligne suivante quand *argsest passé dans l'appel à self.data.popest l'inverse de ceci - le tuple *argsest étendu à des paramètres de position qui sont transmis. Ceci est expliqué dans la référence du langage Python :

Si l'expression syntaxique * apparaît dans l'appel de fonction, l'expression doit s'évaluer en une séquence. Les éléments de cette séquence sont traités comme s'il s'agissait d'arguments positionnels supplémentaires

En bref, a.pop()veut être flexible et accepter n'importe quel nombre de paramètres de position, afin de pouvoir transmettre ce nombre inconnu de paramètres de position à self.data.pop().

Cela vous donne de la flexibilité; datase trouve être un en dictce moment, et self.data.pop()prend donc un ou deux paramètres; mais si vous deviez dataêtre un type qui prenait 19 paramètres pour un appel, self.data.pop()vous n'auriez pas du tout à changer de classe a. Vous devrez quand même changer tout code qui a appelé a.pop()pour passer les 19 paramètres requis.

James Polley
la source
2
+1 pour l'effort. Je crains que l'anglais du PO ne soit pas à la hauteur de votre réponse.
mechanical_meat
J'ai écrit cela avant de lire le profil des OP. J'ai maintenant lu ledit profil et vu plusieurs autres questions sur les PO. Je viens de faire une autre tentative, cette fois en utilisant uniquement du code :)
James Polley
6
def func(*args): 
    pass

Lorsque vous définissez une fonction de cette façon, *argsun tableau d'arguments sera transmis à la fonction. Cela permet à votre fonction de fonctionner sans savoir à l'avance combien d'arguments vont lui être transmis.

Vous faites cela aussi avec des arguments de mots-clés, en utilisant **kwargs:

def func2(**kwargs): 
    pass

Voir: Listes d'arguments arbitraires


Dans votre cas, vous avez défini une classe qui agit comme un dictionnaire. La dict.popméthode est définie comme pop(key[, default]).

Votre méthode n'utilise pas le defaultparamètre. Mais, en définissant votre méthode avec *argset en passant *argsà dict.pop(), vous autorisez l'appelant à utiliser le defaultparamètre.

En d'autres termes, vous devriez pouvoir utiliser la popméthode de votre classe comme dict.pop:

my_a = a()
value1 = my_a.pop('key1')       # throw an exception if key1 isn't in the dict
value2 = my_a.pop('key2', None) # return None if key2 isn't in the dict
Seth
la source
6
>>> def func(a, *args, **kwargs):
...   print 'a %s, args %s, kwargs %s' % (a, args, kwargs)
... 
>>> func('one', 'two', 'three', four='four', five='five')
a one, args ('two', 'three'), kwargs {'four': 'four', 'five': 'five'}

>>> def anotherfunct(beta, *args):
...   print 'beta %s, args %s' % (beta, args)
... 
>>> def func(a, *args, **kwargs):
...   anotherfunct(a, *args)
... 
>>> func('one', 'two', 'three', four='four', five='five')
beta one, args ('two', 'three')
>>> 
James Polley
la source
1
J'ai lu plusieurs questions, comme détaillé dans mon autre réponse. J'ai également lu le profil des OP et réalisé que mon autre réponse est inutile. Cette réponse devrait démontrer au moins une partie de ce que fait * args, ce que je suppose que la vraie confusion des OP est, malgré le sujet.
James Polley
@James, +1 pour l'effort supplémentaire. J'étais arrivé à la même conclusion sur la vraie question.
Peter Hansen