Превращение строки в переменную

Изучал способы форматирования и наткнулся на такую штуку :

test = 'Name'
exec('{0} = {1}'.format(test, 10))
a = Name # Python жалуется на Unresolved reference 'Name' При этом код воспроизводится без ошибок.
print(a) # Вывод: 10  Где в данный момент хранится переменная Name?
print(Name-5) # Вывод: 5
print(test) # Вывод: 'Name'

Первый вопрос, что это такое и почему это вообще работает? Вот аналогичная запись с помощью %-форматирования :

exec('%s = %d' % (test, 10)) # Работает так же как и метод .format() - без проблем.

А вот аналогичная запись с помощью f-форматирования почему-то уже не работает :

exec(f'{(test := 10)}') # Эквивалентная запись с помощью f-форматирования выдаёт NameError: name 'Name' is not defined. Did you mean: 'name'? То есть как и должно работать.

Собственно второй вопрос, чем f-строки отличаются от других видов форматирования при воспроизведении вышеописанного кода? Почему только здесь не работает?


Ответы (1 шт):

Автор решения: CrazyElf

А давайте попробуем не делать exec, а напечатаем ваши строки. И в конце ещё напечатаем значение переменной test:

test = 'Name'
print('{0} = {1}'.format(test, 10))
print('%s = %d' % (test, 10))
print(f'{(test := 10)}')
print(test)

Вывод:

Name = 10
Name = 10
10
10

Ой как интересно. Первые два exec выполняют действие Name = 10. А последний ваш exec выполняет то, что возвращает действие test := 10 после того, как его результат преобразован в строку. Если бы вы написали test = 10, то сразу бы поняли, в чём ошибка. И я подозреваю, что вы так и сделали, и только после этого поменяли = на :=, потому что так было написано в подсказке в ошибке:

SyntaxError: f-string: invalid syntax. Maybe you meant '==' or ':=' instead of '='?

То есть тут сначала делается действие test := 10, а потом уже то, что получается при этом присваивании через "моржовый оператор", пытается выполниться через exec.

Кстати, отдельно непонятно, как вы умудрились в этой строке получить ошибку с "Name". Извольте предоставить полный трейс ошибки, меня терзают смутные сомнения, что код был какой-то другой у вас при этой ошибке. Текущее содержимое переменной test в этом действии совсем никак не участвует, поэтому "Name" там не откуда взяться.

Резюмирую. Не важно, как вы сгенерировали строку, с помощью какого стиля форматирования, exec всегда работает одинаково, если строка одинаковая. Чудес не бывает. А вот операторы x = y и x := y работают немного по-разному. И обычное присваивание вы не сможете написать в f-строке при выводе переменной. Но если сделаете такую же строку, как и предыдущие, то всё будет как раньше, см. комментарий strawdog.

→ Ссылка