Dlaczego musisz wywoływać .items () podczas iteracji po słowniku w Pythonie?

131

Dlaczego musisz wywoływać, items()aby iterować po parach klucz i wartość w słowniku? to znaczy.

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

Dlaczego nie jest to domyślne zachowanie przy iterowaniu po słowniku

for k, v in dic:
    print(k, v)
Falmarri
źródło

Odpowiedzi:

171

Oczekiwanie jest takie dla każdego kontenera Pythona C

for item in C:
    assert item in C

przejdzie w porządku - nie możesz znaleźć to zadziwiające, jeśli jeden zmysł in(klauzula pętla) miał zupełnie inne znaczenie od innych (sprawdzania obecności)? Z pewnością! To oczywiście działa w ten sposób w przypadku list, zestawów, krotek, ...

Tak więc, gdy Cjest słownikiem, gdyby inw forpętli uzyskać krotki klucz / wartość , to zgodnie z zasadą najmniejszego zdziwienia inmusiałby również przyjąć taką krotkę jako operand po lewej stronie podczas sprawdzania zawartości.

Jak przydatne byłoby to? Rzeczywiście całkiem bezużyteczne, po prostu tworząc if (key, value) in Csynonim if C.get(key) == value- co jest sprawdzianem, który, jak sądzę, mogłem wykonać lub chciałem wykonać 100 razy rzadziej niż to, co w if k in Crzeczywistości oznacza , sprawdzając obecność tylko klucza i całkowicie ignorując wartość.

Z drugiej strony chęć zapętlenia tylko na klawiszach jest dość powszechna, np .:

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

posiadanie wartości również nie pomogłoby szczególnie:

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

w rzeczywistości nieco mniej jasne i mniej zwięzłe. (Zauważ, że itemsbyła to oryginalna pisownia "właściwych" metod do uzyskiwania par klucz / wartość: niestety było to w czasach, gdy takie metody dostępu zwracały całe listy, więc aby obsługiwać "tylko iterację" trzeba było wprowadzić alternatywną pisownię i iteritems było - w Pythonie 3, gdzie ograniczenia kompatybilności wstecznej z poprzednimi wersjami Pythona zostały znacznie osłabione, stało się itemsponownie).

Alex Martelli
źródło
10

Moje przypuszczenie: użycie pełnej krotki byłoby bardziej intuicyjne w przypadku zapętlania, ale być może mniej w przypadku testowania pod kątem członkostwa in.

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

Ten kod tak naprawdę nie działałby, gdybyś musiał określić zarówno klucz, jak i wartość in. Trudno mi sobie wyobrazić przypadek użycia, w którym można sprawdzić, czy zarówno klucz ORAZ wartość znajdują się w słowniku. O wiele bardziej naturalne jest testowanie samych kluczy.

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

Teraz nie jest konieczne, aby inoperator i for ... inoperowali na tych samych elementach. Pod względem wdrożeniowym są to różne operacje ( __contains__vs. __iter__). Ale ta mała niespójność byłaby nieco zagmatwana i, no cóż, niespójna.

John Kugelman
źródło
Biorąc pod uwagę, że dla każdego innego typu wbudowanego iterowalnego, o jakim mogę pomyśleć, x in footylko jeśli iw pewnym momencie for i in fooprzyjmie wartość x, powiedziałbym, że byłaby to bardzo duża niespójność.
aaronasterling