Що таке дивна поведінка товстої кишки?


104

Я використовую Python 3.6.1, і мені траплялося щось дуже дивне. У мене був простий типовий склад словника, який знадобився мені довго.

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

Вихід

{}

Що context["a"]: 2робить код ? Він не піднімає, SyntaxErrorколи повинен ІМО. Спочатку я подумав, що це створює шматочок. Однак введення тексту repr(context["a"]: 2)піднімає a SyntaxError. Я також набрав context["a"]: 2консоль, і консоль нічого не надрукувала. Я думав, може, це повернулося None, але я не такий впевнений.

Я також думав, що це може бути один рядок, якщо заява, але це також не повинен бути правильним синтаксисом.

Крім того, context["a"]слід підняти 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 .


12
Чи не повинен це вимагати =оператора призначення? Ключ не існує. Це просто мені не так.
justengel

1
У цьому випадку : є оператором присвоєння. Ми просто "призначаємо" анотацію типу лише, а не ключову. Я сумніваюся, що є якась причина, щоб дозволити це, лише ненавмисний побічний вплив на додавання синтаксису приміток.
чепнер

1
@chepner Здається, це не побічний ефект. Саме так було розроблено відповідне ПЕП.
Ма0

6
Дивно, що це дозволить вам коментувати ціль, яка ще не визначена. Якщо мій перший рядок є x: strі одразу після нього type(x), перекладач підніме «а» NameError. Синтаксис IMO повинен примушувати об'єкт заздалегідь визначений або визначений на місці. Це просто вносить плутанину.
r.ook

2
@Idlehands Це перемагає мету. Якщо x = 'i am a string'до цього x: strзробити останній вид надмірним. Це взагалі не слід було додавати. Це було добре як коментар; Я ніколи не показую, що він використовувався так чи інакше.
Ма0
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.