Em Python, o que dict.pop (a, b) significa?

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 que existe um segundo argumento?

zjm1126
fonte
8
Ou se você for realmente preguiçoso help(b.data.pop)no REPL.
Michael Mior

Respostas:

120

O popmétodo de dicts (como self.data, isto é {'a':'aaa','b':'bbb','c':'ccc'}, aqui) leva dois argumentos - veja a documentação

O segundo argumento,, defaulté o que popretorna se o primeiro argumento key,, estiver ausente. (Se você chamar popcom apenas um argumento key,, ele gerará uma exceção se essa chave estiver ausente).

Em seu exemplo, print b.pop('a',{'b':'bbb'})isso é irrelevante porque 'a' é uma chave em b.data. Mas se você repetir essa linha ...:

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

você verá que faz diferença: o primeiro popremove a 'a'chave, então no segundo popo defaultargumento é realmente retornado (já que 'a'agora está ausente de b.data).

Alex Martelli
fonte
3
Apenas um pequeno comentário que eu acho importante em algumas situações onde o usuário precisa de popum elemento, dictmas retém o valor do elemento exibido. Portanto, dict.pop(key)remove o keyjunto com o associado, valuemas também retorna o valuedo keyque acabou de ser removido. Achei útil ...
flamenco
@flamenco é isso que eu espero pop()- comportamento comum em mais linguagens como JavaScript, PHP, Java, embora nem todas as linguagens façam isso - por exemplo, C ++.
jave.web
27

Tantas perguntas aqui. Eu vejo pelo menos dois, talvez três:

  • O que pop (a, b) faz? / Por que há um segundo argumento?
  • Para que está *argssendo usado?

A primeira pergunta é trivialmente respondida na referência da Biblioteca Padrão do Python :

pop (tecla [, padrão])

Se a chave estiver no dicionário, remova-a e retorne seu valor, caso contrário, retorne o padrão. Se o padrão não for fornecido e a chave não estiver no dicionário, um KeyError é gerado.


A segunda pergunta é abordada na Referência da linguagem Python :

Se a forma “* identificador” estiver presente, ele é inicializado com uma tupla recebendo quaisquer parâmetros posicionais em excesso, assumindo como padrão a tupla vazia. Se a forma “** identificador” estiver presente, ele é inicializado para um novo dicionário recebendo quaisquer argumentos de palavra-chave em excesso, assumindo como padrão um novo dicionário vazio.

Em outras palavras, a popfunção leva pelo menos dois argumentos. Os dois primeiros recebem os nomes selfe key; e o resto é colocado em uma tupla chamada args.

O que acontece na próxima linha quando *argsé transmitido na chamada de self.data.popé o inverso disso - a tupla *argsé expandida para dos parâmetros posicionais que são transmitidos. Isso é explicado na Referência da linguagem Python :

Se a sintaxe * expressão aparecer na chamada de função, a expressão deve ser avaliada como uma sequência. Os elementos desta sequência são tratados como se fossem argumentos posicionais adicionais

Resumindo, a.pop()quer ser flexível e aceitar qualquer número de parâmetros posicionais, de modo que possa passar esse número desconhecido de parâmetros posicionais para self.data.pop().

Isso lhe dá flexibilidade; datapassa a ser um dictagora e, portanto, self.data.pop()leva um ou dois parâmetros; mas se você mudar datapara um tipo que usa 19 parâmetros para uma chamada para, self.data.pop()você não terá que mudar de classe a. Você ainda teria que alterar qualquer código chamado a.pop()para passar os 19 parâmetros necessários.

James Polley
fonte
2
1 pelo esforço. Temo que o inglês do OP não esteja à altura de ler sua resposta.
Mechanical_meat
Eu escrevi isso antes de ler o perfil dos OPs. Agora li o referido perfil e vi várias outras perguntas sobre os OPs. Acabei de fazer outra tentativa, desta vez usando apenas código :)
James Polley
6
def func(*args): 
    pass

Quando você define uma função dessa maneira, *argsum array de argumentos é passado para a função. Isso permite que sua função funcione sem saber com antecedência quantos argumentos serão passados ​​para ela.

Você também faz isso com argumentos de palavra-chave, usando **kwargs:

def func2(**kwargs): 
    pass

Veja: Listas de argumentos arbitrários


No seu caso, você definiu uma classe que funciona como um dicionário. O dict.popmétodo é definido como pop(key[, default]).

Seu método não usa o defaultparâmetro. Mas, ao definir seu método com *argse passar *argspara dict.pop(), você está permitindo que o chamador use o defaultparâmetro.

Em outras palavras, você deve ser capaz de usar o popmétodo de sua classe 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
fonte
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
fonte
1
Li várias perguntas, conforme detalhado na minha outra resposta. Também li o perfil dos OPs e percebi que minha outra resposta é inútil. Essa resposta deve demonstrar pelo menos parte do que * args faz, que é o que estou supondo que seja a verdadeira confusão dos OPs, apesar do assunto.
James Polley
@James, +1 pelo esforço extra. Eu cheguei à mesma conclusão sobre a questão real.
Peter Hansen