Cosa sta facendo questo strano comportamento del colon?


104

Sto usando Python 3.6.1 e mi sono imbattuto in qualcosa di molto strano. Ho avuto un semplice errore di battitura per l'assegnazione del dizionario che mi ha richiesto molto tempo per trovare.

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

Produzione

{}

Cosa sta context["a"]: 2facendo il codice ? Non solleva un SyntaxErrorquando dovrebbe IMO. All'inizio ho pensato che stesse creando una fetta. Tuttavia, la digitazione repr(context["a"]: 2)solleva a SyntaxError. Ho anche digitato context["a"]: 2nella console e la console non ha stampato nulla. Ho pensato che forse fosse tornato None, ma non ne sono così sicuro.

Ho anche pensato che potesse essere una singola riga di istruzione if, ma nemmeno quella dovrebbe essere la sintassi corretta.

Inoltre, context["a"]dovrebbe aumentare a KeyError.

Sono perplesso. Cosa sta succedendo?


2
Questa domanda ha già un dupe ed è abbastanza chiaro che questo crea confusione per i principianti di Python. Immagino che questo sia peggio se Python è la tua unica lingua, dove i suggerimenti sul tipo e la definizione delle variabili prima dell'inizializzazione in generale potrebbero sembrare estranei. Immagino che sollevare un errore sia impossibile poiché questo comportamento è intenzionale e talvolta utile come spiegato in PEP 526, e non vuoi infrangere la compatibilità. Tuttavia, mi chiedo se gli sviluppatori di Python considererebbero l'aggiunta di un utile messaggio di avviso per alcuni casi.
Chris_Rands

Risposte:


98

Hai scritto accidentalmente un'annotazione di variabile sintatticamente corretta . Questa funzionalità è stata introdotta in Python 3.6 (vedere PEP 526 ).

Sebbene un'annotazione di variabile venga analizzata come parte di un assegnamento annotato , l'istruzione di assegnazione è facoltativa :

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

Quindi, in context["a"]: 2

  • context["a"] è l'obiettivo dell'annotazione
  • 2 è l'annotazione stessa
  • context["a"] è lasciato non inizializzato

Il PEP afferma che "l'obiettivo dell'annotazione può essere un qualsiasi obiettivo di assegnazione singolo valido, almeno sintatticamente (dipende dal controllo del tipo cosa fare con questo)" , il che significa che la chiave non deve esistere per essere annotato (quindi no KeyError). Ecco un esempio dal PEP originale:

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

Normalmente, l'espressione di annotazione dovrebbe essere valutata come un tipo Python - dopo tutto l'uso principale delle annotazioni è il suggerimento sul tipo, ma non viene applicato. L'annotazione può essere qualsiasi espressione Python valida , indipendentemente dal tipo o dal valore del risultato.

Come puoi vedere, in questo momento i suggerimenti sul tipo sono molto permissivi e raramente utili, a meno che tu non abbia un controllo del tipo statico come mypy .


12
Non dovrebbe quindi richiedere un =operatore di assegnazione? La chiave non esiste. Questo mi sembra solo sbagliato.
justengel

1
In questo caso, : è l'operatore di assegnazione. Stiamo solo "assegnando" un'annotazione di tipo da sola, non una chiave. Dubito che ci sia una ragione per consentirlo, solo un effetto collaterale non intenzionale dell'aggiunta della sintassi dell'annotazione.
chepner

1
@chepner Sembra che questo non sia un effetto collaterale imho. Questo è esattamente ciò per cui è stato progettato il PEP corrispondente.
maggio

6
È strano che ti permetta di annotare un obiettivo che non è stato ancora definito. Se la mia prima riga è x: strimmediatamente seguita da type(x), l'interprete solleverà a NameError. IMO la sintassi dovrebbe far rispettare l'oggetto è predefinito o è definito sul posto. Questo introduce solo confusione.
r.ook

2
@Idlehands Questo però sconfigge lo scopo. Avere x = 'i am a string'prima x: strrende ridondante quest'ultimo tipo .. Questo non avrebbe dovuto essere aggiunto affatto. Andava bene come commento; Non lo mostro mai usato in un modo o nell'altro.
maggio
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.