En Python, ¿qué significa 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) ← ------ ¿por qué hay un segundo argumento?

zjm1126
fuente
8
O si eres realmente vago help(b.data.pop)en REPL.
Michael Mior

Respuestas:

120

El popmétodo de dictados (como self.data, es decir {'a':'aaa','b':'bbb','c':'ccc'}, aquí) toma dos argumentos: consulte los documentos

El segundo argumento,, defaultes lo que popregresa si el primer argumento key,, está ausente. (Si llama popcon un solo argumento, keygenera una excepción si esa clave está ausente).

En su ejemplo, print b.pop('a',{'b':'bbb'})esto es irrelevante porque 'a' es una clave b.data. Pero si repites esa línea ...:

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

verá que hace una diferencia: el primero popelimina la 'a'clave, por lo que en el segundo popel defaultargumento se devuelve realmente (ya 'a'que ahora está ausente b.data).

Alex Martelli
fuente
3
Solo un pequeño comentario que creo que es importante en algunas situaciones en las que el usuario necesita popun elemento dictpero retiene el valor del elemento emergente. Por lo tanto, dict.pop(key)elimina el keyjunto con el asociado, valuepero también devuelve valueel keyque acaba de eliminarse. Lo encontré útil ...
flamenco
@flamenco eso es lo que espero de pop()- comportamiento común en más lenguajes como JavaScript, PHP, Java, aunque no todos los lenguajes hacen eso - por ejemplo, C ++.
jave.web
27

Tantas preguntas aquí. Veo al menos dos, tal vez tres:

  • ¿Qué hace pop (a, b)? / ¿Por qué hay un segundo argumento?
  • ¿Para qué se *argsutiliza?

La primera pregunta se responde de manera trivial en la referencia de la biblioteca estándar de Python :

pop (tecla [, predeterminado])

Si la clave está en el diccionario, elimínela y devuelva su valor; de lo contrario, devuelva el valor predeterminado. Si no se proporciona el valor predeterminado y la clave no está en el diccionario, se genera un KeyError.


La segunda pregunta se cubre en la Referencia del lenguaje Python :

Si la forma "* identificador" está presente, se inicializa a una tupla que recibe cualquier parámetro posicional en exceso, por defecto a la tupla vacía. Si la forma "** identificador" está presente, se inicializa a un nuevo diccionario que recibe cualquier exceso de argumentos de palabras clave, por defecto a un nuevo diccionario vacío.

En otras palabras, la popfunción toma al menos dos argumentos. A los dos primeros se les asignan los nombres selfy key; y el resto se rellena en una tupla llamada args.

Lo que sucede en la siguiente línea cuando *argsse pasa en la llamada a self.data.popes lo contrario: la tupla *argsse expande a los parámetros posicionales que se transmiten. Esto se explica en la Referencia del lenguaje Python :

Si la sintaxis * expresión aparece en la llamada a la función, la expresión debe evaluarse como una secuencia. Los elementos de esta secuencia se tratan como si fueran argumentos posicionales adicionales

En resumen, a.pop()quiere ser flexible y aceptar cualquier número de parámetros posicionales, de modo que pueda pasar este número desconocido de parámetros posicionales self.data.pop().

Esto le da flexibilidad; datapasa a ser un dictderecho ahora, por lo que self.data.pop()toma uno o dos parámetros; pero si cambiara dataa un tipo que tomara 19 parámetros para una llamada self.data.pop(), no tendría que cambiar la clase aen absoluto. Sin embargo, aún tendría que cambiar cualquier código que llame a.pop()para pasar los 19 parámetros requeridos.

James Polley
fuente
2
+1 por el esfuerzo. Me temo que el inglés del OP no está a la altura de la tarea de leer su respuesta.
mechanical_meat
Escribí eso antes de leer el perfil de OP. Ahora he leído dicho perfil y he visto varias otras preguntas de los OP. Acabo de hacer otro intento, esta vez usando solo código :)
James Polley
6
def func(*args): 
    pass

Cuando defina una función de esta manera, se *argspasará una matriz de argumentos a la función. Esto permite que su función funcione sin saber de antemano cuántos argumentos se le pasarán.

También hace esto con argumentos de palabras clave, usando **kwargs:

def func2(**kwargs): 
    pass

Ver: listas de argumentos arbitrarios


En su caso, ha definido una clase que actúa como un diccionario. El dict.popmétodo se define como pop(key[, default]).

Tu método no usa el defaultparámetro. Pero, al definir su método con *argsy pasar *argsa dict.pop(), está permitiendo que la persona que llama use el defaultparámetro.

En otras palabras, debería poder usar el popmétodo de su clase como 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
fuente
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
fuente
1
Leí varias preguntas, como se detalla en mi otra respuesta. También leí el perfil de OP y me di cuenta de que mi otra respuesta es inútil. Esta respuesta debería demostrar al menos parte de lo que hace * args, que es lo que supongo que es la verdadera confusión de los OP, a pesar del tema.
James Polley
@James, +1 por el esfuerzo extra. Llegué a la misma conclusión sobre la verdadera pregunta.
Peter Hansen