Наткнулся тут в телеграме на интересный вопрос, касающийся поведения переменных в Python. Сам факт, что автор загадки - Гвидо ван Россум уже заслуживает внимания[1]. А ещё подобные головоломки периодически любят задавать на собеседованиях.
Источники вольного перевода и оригинал загадки в конце заметки.
Код задачки:
Похоже дзен немного поправил верстку и после публикации код едет. Скину сюда скрины, а так же прикреплю ссыль на гитхаб с примерами для тех, кто хочет скопировать. [4]
Вопрос - что выведет print?
Разберем, как такое получилось:
первую подсказку мы получим, если заменим класс на функцию:
При запуске мы ловим исключение UnboundLocalError
В чем проблема? Ответ можно найти в главе модель исполнения документации Python [3]
Локальная переменная - переменная, объявленная в блоке кода, если перед ней не указано nonlocal / global.
Глобальные переменные - переменные объявленные на уровне модуля.
Свободная переменная - переменная, используемая в блоке, но не объявленная в нем
Получается, что объявив `x` в том же блоке кода, что и print мы изменили её тип для интерпретатора и соответственно поведение по сравнению с переменной `y`
Дизассемблируем блок кода с функцией:
Самое интересное - как раз описание функции f2()
Мы видим, что для `x` и `y` предусмотрены разные инструкции.
Теперь посмотрим на поведение класса:
И опять мы видим разные инструкции, но класс поступает по другому с переменной `x`. В чем разница? Ищем в документации
Классы обладают отличающимся поведением, когда дело касается exec() / eval(). Если возникает исключение и найдена не объявленная ещё переменная, то проводится поиск среди глобальных переменных, пропуская ближайшую (nonlocal) область видимости.
_________________________________________________________________________________________
Практически любой язык обладает рядом допущений и определенным объемом странного на первый взгляд поведения. Часть из него может всплыть только в искусственно смоделированных ситуациях, часть вполне способна подпортить жизнь в вашем проекте) Предупрежден значит вооружен, теперь одним заковыристым вопросом для собеседований меньше. Или наоборот +1 высказывание для вас, на котором можно заработать очки)
Источники:
[2] оригинал поста в телеграме