Co robi to dziwne zachowanie jelita grubego?

105

Używam Pythona 3.6.1 i natknąłem się na coś bardzo dziwnego. Miałem prostą literówkę w przypisaniu do słownika, której znalezienie zajęło mi dużo czasu.

context = {}
context["a"]: 2
print(context)

Wynik

{}

Co context["a"]: 2robi kod ? Nie zgłasza, SyntaxErrorkiedy powinien IMO. Na początku myślałem, że tworzy kawałek. Jednak wpisywanie repr(context["a"]: 2)podnosi SyntaxError. Wpisałem też context["a"]: 2w konsoli i konsola nic nie wydrukowała. Myślałem, że może wróciło None, ale nie jestem tego taki pewien.

Pomyślałem również, że może to być pojedyncza linia instrukcji if, ale to też nie powinna być właściwa składnia.

Dodatkowo context["a"]powinien podbić KeyError.

Jestem zakłopotany. Co się dzieje?

justengel
źródło
2
Już to pytanie jest dublowane i jest całkiem jasne, że jest to mylące dla nowicjuszy w Pythonie. Wydaje mi się, że jest to najgorsze, jeśli Python jest jedynym językiem, w którym podpowiedzi typu i definicja zmiennych przed inicjalizacją mogą wydawać się obce. Wyobrażam sobie, że zgłoszenie błędu jest niemożliwe, ponieważ takie zachowanie jest celowe i czasami przydatne, jak wyjaśniono w PEP 526, i nie chcesz naruszać zgodności. Zastanawiam się jednak, czy deweloperzy Pythona rozważyliby dodanie przydatnego komunikatu ostrzegawczego w niektórych przypadkach.
Chris_Rands
1
Czy to odpowiada na twoje pytanie? Co to są adnotacje zmiennych w Pythonie 3.6?
Georgy

Odpowiedzi:

98

Przypadkowo napisałeś poprawną składniowo adnotację do zmiennej . Ta funkcja została wprowadzona w Pythonie 3.6 (patrz PEP 526 ).

Chociaż adnotacja zmiennej jest analizowana jako część przypisania z adnotacjami , instrukcja przypisania jest opcjonalna :

annotated_assignment_stmt ::=  augtarget ":" expression ["=" expression]

Tak więc w context["a"]: 2

  • context["a"] jest celem adnotacji
  • 2 to sama adnotacja
  • context["a"] pozostaje niezainicjalizowany

PEP stwierdza, że „celem adnotacji może być dowolny ważny pojedynczy cel przypisania, przynajmniej pod względem składniowym (co z tym zrobić zależy od sprawdzania typu)” , co oznacza, że ​​klucz nie musi istnieć, aby być opatrzone adnotacjami (stąd nie KeyError). Oto przykład z oryginalnego PEP:

d = {}
d['a']: int = 0  # Annotates d['a'] with int.
d['b']: int      # Annotates d['b'] with int.

Zwykle wyrażenie adnotacji powinno być szacowane na typ Pythona - w końcu głównym zastosowaniem adnotacji jest podpowiedź do typu, ale nie jest ona wymuszana. Adnotacja może być dowolnym prawidłowym wyrażeniem Pythona, niezależnie od typu lub wartości wyniku.

Jak widać, w tej chwili podpowiedzi dotyczące typów są bardzo przyzwalające i rzadko przydatne, chyba że masz statyczne narzędzie do sprawdzania typów, takie jak mypy .

vaultah
źródło
12
Czy nie powinno to zatem wymagać =operatora przypisania? Klucz nie istnieje. Po prostu wydaje mi się to złe.
justengel
1
W tym przypadku : jest operatorem przypisania. Po prostu „przypisujemy” samą adnotację typu, a nie klucz. Wątpię, czy jest jakikolwiek powód, by na to zezwolić, tylko niezamierzony efekt uboczny dodania składni adnotacji.
chepner
1
@chepner Wygląda na to, że nie jest to efekt uboczny imho. Właśnie do tego został zaprojektowany odpowiedni PEP.
Ma0
6
To dziwne, że pozwoli ci to dodać adnotację do celu, który nie został jeszcze zdefiniowany. Jeśli moja pierwsza linijka to x: stri zaraz po niej nastąpi type(x), tłumacz podniesie NameError. IMO składnia powinna wymuszać, że obiekt jest wstępnie zdefiniowany lub zdefiniowany na miejscu. To tylko wprowadza zamieszanie.
Obejrzyj
2
@Idlehands To jednak mija się z celem. Posiadanie x = 'i am a string'wcześniejszego x: strsprawia, że ​​ten drugi rodzaj jest zbędny. W ogóle nie powinno być dodawane. To było w porządku jako komentarz; Nigdy nie pokazuję, że był używany w taki czy inny sposób.
Ma0