Что означает dict.pop (a, b) в Python?

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) ← ------ почему тут второй аргумент?

zjm1126
источник
8
Или если вам совсем лень help(b.data.pop)в REPL.
Майкл Миор

Ответы:

121

popМетод dicts (как self.data, например {'a':'aaa','b':'bbb','c':'ccc'}, здесь) принимает два аргумента - см документации

Второй аргумент, defaultэто то, что popвозвращается, если первый аргумент keyотсутствует. (Если вы вызываете popтолько с одним аргументом, keyвозникает исключение, если этот ключ отсутствует).

В вашем примере print b.pop('a',{'b':'bbb'}), это не имеет значения , потому что 'a' является ключевым в b.data. Но если вы повторите эту строку ...:

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

вы увидите , что он делает разницу: первый popУдаляет 'a'ключ, так что во втором аргумент фактически возвращенного (так как в настоящее время отсутствует ).popdefault'a'b.data

Алекс Мартелли
источник
3
Просто небольшой небольшой комментарий, который, я думаю, важен в некоторых ситуациях, когда пользователю нужен popэлемент, dictно сохранить значение всплывающего элемента. Таким образом, dict.pop(key)снимает keyвместе с соответствующим , valueно и возвращает valueиз keyкоторый только что был удален. Я нашел это полезным ...
фламенко
@flamenco - это то, чего я ожидаю pop()- обычное поведение для большего количества языков, таких как JavaScript, PHP, Java, хотя не все языки делают это - например, C ++.
jave.web
27

Здесь так много вопросов. Я вижу как минимум два, может, три:

  • Что делает pop (a, b)? / Почему есть второй аргумент?
  • Для *argsчего используется?

На первый вопрос тривиальный ответ дан в справочнике по стандартной библиотеке Python :

pop (клавиша [, по умолчанию])

Если ключ находится в словаре, удалите его и верните его значение, иначе верните значение по умолчанию. Если значение по умолчанию не указано и ключ отсутствует в словаре, возникает ошибка KeyError.


Второй вопрос рассматривается в Справочнике по языку Python :

Если присутствует форма «* идентификатор», она инициализируется кортежем, получающим любые избыточные позиционные параметры, по умолчанию - пустой кортеж. Если присутствует форма «** идентификатор», она инициализируется новым словарем, получающим любые избыточные аргументы ключевого слова, по умолчанию используется новый пустой словарь.

Другими словами, popфункция принимает как минимум два аргумента. Первым двум присваиваются имена selfи key; а остальные помещаются в кортеж с именем args.

То, что происходит в следующей строке, когда *argsпередается в вызове, self.data.popявляется обратным этому - кортеж *argsрасширяется до позиционных параметров, которые передаются. Это объясняется в Справочнике по языку Python :

Если в вызове функции появляется синтаксис * выражение, выражение должно оцениваться как последовательность. Элементы из этой последовательности обрабатываются, как если бы они были дополнительными позиционными аргументами

Короче говоря, он a.pop()хочет быть гибким и принимать любое количество позиционных параметров, чтобы он мог передать это неизвестное количество позиционных параметров self.data.pop().

Это дает вам гибкость; dataоказывается dictпрямо сейчас и поэтому self.data.pop()принимает один или два параметра; но если вы изменили dataтип, который принимает 19 параметров для вызова, self.data.pop()вам вообще не придется менять класс a. Однако вам все равно придется изменить любой код, который вызывается a.pop()для передачи необходимых 19 параметров.

Джеймс Полли
источник
2
+1 за усилия. Боюсь, что английский OP не подходит для чтения вашего ответа.
Mechanical_meat
Я написал это до того, как прочитал профиль OP. Теперь я прочитал указанный профиль и увидел несколько других вопросов OP. Я только что сделал еще одну попытку, на этот раз используя только код :)
Джеймс Полли
7
def func(*args): 
    pass

Когда вы определяете функцию таким образом, в функцию *argsбудет передан массив аргументов. Это позволяет вашей функции работать, не зная заранее, сколько аргументов ей будет передано.

Вы также делаете это с аргументами ключевого слова, используя **kwargs:

def func2(**kwargs): 
    pass

См .: Списки произвольных аргументов


В вашем случае вы определили класс, который действует как словарь. dict.popМетод определяется как pop(key[, default]).

Ваш метод не использует defaultпараметр. Но, определяя свой метод с помощью *argsи передавая *argsему dict.pop(), вы разрешаете вызывающему объекту использовать defaultпараметр.

Другими словами, вы должны иметь возможность использовать popметод своего класса, например 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
Сет
источник
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')
>>> 
Джеймс Полли
источник
1
Я прочитал несколько вопросов, подробно описанных в моем другом ответе. Я также прочитал профиль OP и понял, что мой другой ответ бесполезен. Этот ответ должен продемонстрировать по крайней мере часть того, что делает * args, что, как я предполагаю, вызывает настоящую путаницу OP, несмотря на предмет.
Джеймс Полли
@ Джеймс, +1 за дополнительные усилия. Я пришел к такому же выводу по поводу настоящего вопроса.
Питер Хансен