Почему вы должны вызывать .items () при переборе словаря в Python?

131

Почему вам нужно вызывать items()для перебора пар ключ, значение в словаре? то есть.

dic = {'one': '1', 'two': '2'}
for k, v in dic.items():
    print(k, v)

Почему это не стандартное поведение перебора словаря

for k, v in dic:
    print(k, v)
Falmarri
источник

Ответы:

171

Ожидается, что для каждого контейнера Python C

for item in C:
    assert item in C

пройдет нормально - не вы найдете это удивительно , если один смысл in(клаузулы цикла) имел совершенно иное значение от других (проверок присутствия)? Я уверен, что будет! Это естественно работает для списков, наборов, кортежей, ...

Итак, когда Cэто словарь, если бы inв forцикле были получены кортежи ключ / значение , тогда, по принципу наименьшего удивления, inон также должен был бы взять такой кортеж в качестве своего левого операнда при проверке содержания.

Насколько это было бы полезно? Довольно бесполезный действительно, в основном делает if (key, value) in Cсиноним if C.get(key) == value- что проверка Я считаю , что , возможно, выполнены, или хотел выполнить, в 100 раз реже , чем то , что на if k in Cсамом деле означает , проверка наличия ключа только и полностью игнорируя значение.

С другой стороны, довольно часто возникает желание зацикливаться только на клавишах, например:

for k in thedict:
    thedict[k] += 1

наличие значения тоже не поможет:

for k, v in thedict.items():
    thedict[k] = v + 1

на самом деле несколько менее ясный и менее лаконичный. (Обратите внимание, что это itemsбыло исходное написание «правильных» методов для использования для получения пар ключ / значение: к сожалению, это было еще в те дни, когда такие методы доступа возвращали целые списки, поэтому для поддержки «простого повторения» пришлось ввести альтернативное написание , и iteritems было - в Python 3, где ограничения обратной совместимости с предыдущими версиями Python были значительно ослаблены, стало itemsснова).

Алекс Мартелли
источник
10

Мое предположение: использование полного кортежа было бы более интуитивно понятным для цикла, но, возможно, в меньшей степени для тестирования использования членства in.

if key in counts:
    counts[key] += 1
else:
    counts[key] = 1

Этот код не работал бы, если бы вам нужно было указать и ключ, и значение для in. Мне сложно представить вариант использования, в котором вы бы проверили, есть ли в словаре значение ключа И. Намного естественнее проверять только ключи.

# When would you ever write a condition like this?
if (key, value) in dict:

Теперь не обязательно, чтобы inоператор и for ... inоперировали одними и теми же объектами. С точки зрения реализации это разные операции ( __contains__vs. __iter__). Но это небольшое несоответствие может сбить с толку и, ну, в общем, непоследовательно.

Джон Кугельман
источник
Учитывая, что для любого другого типа встроенной итерации, о котором я могу думать, x in fooтолько если iin в какой-то момент for i in fooпринимает значение x, я бы сказал, что это будет очень огромная несогласованность.
aaronasterling