Найти тему

Python головоломка

Наткнулся тут в телеграме на интересный вопрос, касающийся поведения переменных в Python. Сам факт, что автор загадки - Гвидо ван Россум уже заслуживает внимания[1]. А ещё подобные головоломки периодически любят задавать на собеседованиях.

Источники вольного перевода и оригинал загадки в конце заметки.

Код задачки:

Похоже дзен немного поправил верстку и после публикации код едет. Скину сюда скрины, а так же прикреплю ссыль на гитхаб с примерами для тех, кто хочет скопировать. [4]

Вопрос - что выведет print?

-2

Разберем, как такое получилось:

первую подсказку мы получим, если заменим класс на функцию:

-4

При запуске мы ловим исключение UnboundLocalError

-5

В чем проблема? Ответ можно найти в главе модель исполнения документации Python [3]

Локальная переменная - переменная, объявленная в блоке кода, если перед ней не указано nonlocal / global.
Глобальные переменные - переменные объявленные на уровне модуля.
Свободная переменная - переменная, используемая в блоке, но не объявленная в нем

Получается, что объявив `x` в том же блоке кода, что и print мы изменили её тип для интерпретатора и соответственно поведение по сравнению с переменной `y`

Дизассемблируем блок кода с функцией:

-6

Самое интересное - как раз описание функции f2()

-7

Мы видим, что для `x` и `y` предусмотрены разные инструкции.

Теперь посмотрим на поведение класса:

-8

-9

И опять мы видим разные инструкции, но класс поступает по другому с переменной `x`. В чем разница? Ищем в документации

Классы обладают отличающимся поведением, когда дело касается exec() / eval(). Если возникает исключение и найдена не объявленная ещё переменная, то проводится поиск среди глобальных переменных, пропуская ближайшую (nonlocal) область видимости.

_________________________________________________________________________________________

Практически любой язык обладает рядом допущений и определенным объемом странного на первый взгляд поведения. Часть из него может всплыть только в искусственно смоделированных ситуациях, часть вполне способна подпортить жизнь в вашем проекте) Предупрежден значит вооружен, теперь одним заковыристым вопросом для собеседований меньше. Или наоборот +1 высказывание для вас, на котором можно заработать очки)

Источники:

[1] пост автора с загадкой

[2] оригинал поста в телеграме

[3] Execution model python docs

[4] гитхаб с примерами