Что делает это странное поведение толстой кишки?

105

Я использую Python 3.6.1 и наткнулся на кое-что очень странное. У меня была простая опечатка в задании словаря, которую я долго искал.

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

Вывод

{}

Что context["a"]: 2делает код ? Он не поднимает, SyntaxErrorкогда должен, ИМО. Сначала я подумал, что это создает срез. Однако при вводе repr(context["a"]: 2)файла SyntaxError. Я также набрал context["a"]: 2в консоли, и консоль ничего не печатала. Думал, может, вернулось None, но не уверен.

Я также подумал, что это может быть однострочный оператор if, но это тоже не должен быть правильным синтаксисом.

Кроме того, context["a"]следует поднять файл KeyError.

Я в недоумении. Что происходит?

Джастенгель
источник
2
В этом вопросе уже есть обман, и довольно ясно, что это сбивает с толку новичков в Python. Я думаю, это хуже всего, если Python - ваш единственный язык, где подсказки типов и определение переменных до инициализации в целом могут показаться чуждыми. Я полагаю, что создание ошибки невозможно, поскольку такое поведение является преднамеренным и иногда полезным, как описано в PEP 526, и вы не хотите нарушать совместимость. Однако мне интересно, рассмотрят ли разработчики Python возможность добавления полезного предупреждающего сообщения для некоторых случаев.
Chris_Rands
1
Отвечает ли это на ваш вопрос? Что такое аннотации переменных в Python 3.6?
Георгий

Ответы:

98

Вы случайно написали синтаксически правильную аннотацию переменной . Эта функция была представлена ​​в Python 3.6 (см. PEP 526 ).

Хотя аннотация переменной анализируется как часть аннотированного присваивания , оператор присваивания является необязательным :

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

Таким образом, в context["a"]: 2

  • context["a"] цель аннотации
  • 2 сама аннотация
  • context["a"] остается неинициализированным

В PEP указано, что «целью аннотации может быть любая допустимая единственная цель назначения, по крайней мере, синтаксически (что с этим делать - зависит от проверяющего типа)» , что означает, что ключ не обязательно должен существовать, чтобы быть аннотированный (следовательно, нет KeyError). Вот пример из оригинального PEP:

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

Обычно выражение аннотации должно оцениваться как тип Python - в конце концов, основное использование аннотаций - это подсказка типа, но она не применяется. Аннотацией может быть любое допустимое выражение Python, независимо от типа или значения результата.

Как видите, в настоящее время подсказки типов очень разрешительны и редко полезны, если только у вас нет средства проверки статического типа, такого как mypy .

Vaultah
источник
12
Разве для этого не нужен =оператор присваивания? Ключ не существует. Мне это кажется неправильным.
justengel
1
В данном случае : это оператор присваивания. Мы просто «назначаем» только аннотацию типа, а не ключ. Я сомневаюсь, что для этого есть какая-то причина, просто непреднамеренный побочный эффект добавления синтаксиса аннотации.
chepner
1
@chepner Кажется, это не побочный эффект, имхо. Именно для этого и был разработан соответствующий PEP.
Ma0
6
Странно, что это позволит вам аннотировать цель, которая еще не была определена. Если моя самая первая строка - x: strи сразу за ней type(x), интерпретатор вызовет NameError. IMO синтаксис должен обеспечивать, чтобы объект был предварительно определен или определен на месте. Это просто вносит путаницу.
r.ook
2
@Idlehands Но это противоречит цели. Наличие x = 'i am a string'до x: strделает последний вид излишним. Его вообще не следовало добавлять. Это было прекрасно в качестве комментария; Я никогда не показываю, что это использовалось так или иначе.
Ma0