Python exec не работает

exec() не работает внутри функции python3.x

Я пытаюсь запустить этот код, но кажется, что exec() не выполняет строку внутри функции:

def abc(xyz): for i in fn_lst: s = 'temp=' + i + '(xyz)' exec(s) print (temp) abc('avdfbafadnf') 
NameError Traceback (most recent call last) in () ----> 1 abc('avdfbafadnf') in abc(xyz) 4 s = 'temp=' + i + '(word)' 5 exec(s) ----> 6 print (temp) NameError: name 'temp' is not defined 

fn_lst это список имен функций т.е. [‘has_at’, ‘has_num’ . ]

Пожалуйста, дайте мне знать альтернативу exec() если возможно в таком сценарии.

5 ответов

Вместо того, чтобы использовать exec с именами функций просто сохраните объекты функций в списке:

и выполнить звонок напрямую:

def abc(xyz): for i in fn_lst: temp= i(xyz) print(temp) 

Чтобы сделать переменную, заданную строкой, переданной exec(), доступной вне вызова, используйте exec () следующим образом:

exec( a_string, locals(), globals() ) 
exec( 'a = 3', locals(), globals() ) print( a ) 

напечатает следующий результат:

У меня недостаточно очков репутации для добавления комментариев, но я хотел бы упомянуть, что предыдущий ответ DrM не работает (внутри функции):

def test(): exec( 'a = 3', globals(), locals() ) print(a) test() 

Этот код дает ошибку в Python 3:

NameError: name 'a' is not defined 

Я пробовал несколько методов, используя compile функция, предложенная на других форумах, но она все еще не работает для меня (по крайней мере, с упомянутыми мною вариантами).

Я считаю, что это очень важная тема. Иногда, когда вы работаете с библиотеками символьной алгебры, такими как Sympy, определяя переменные через exec Функция может быть очень удобной в научных вычислениях.

Надеюсь, кто-нибудь знает хороший ответ на проблему.

PS. Согласно моим исследованиям, это ближайший код, который я видел работающим:

def test(): lcls = locals() exec( 'a = 3', globals(), lcls ) a = lcls["a"] print('a is %d' %a) test() 

Потратив так много времени на попытки решить эту проблему, я могу сказать, что использование exec, подобного этому, работало без каких-либо проблем внутри функции, в противном случае возникала ошибка. Я проверил это как для функций, так и для переменных.

def main(): x = "def y():\n\treturn('This will work')" #pass only globals() not locals() exec(x,globals()) print(y()) main() def test(): #pass only globals() not locals() exec( 'a = 3', globals()) print(a) test() 

Вот скриншот этой работы над онлайн-интерпретатором W3School (вы можете скопировать / вставить и протестировать его здесь самостоятельно)

Я ищу эту проблему, потому что я пытался импортировать переменные файла конфигурации в функцию, но это не удалось.

После недолгих проб я пришел к следующим выводам:

  1. globals()[‘a’]=1 может изменять глобальные переменные.
  2. locals()[‘a’]=1 не может изменять локальные переменные в текущей области, если текущая область не является «основной», где id(locals())==id(globals()).
Читайте также:  Java узнать тип переменной

Вот почему exec() для locals() работает в «основной» области, но не работает внутри функции.

Я думаю, что это ловушка механизма области видимости Python.

Источник

Блог

команда python exec работает в консоли, но не в программе

#python #python-3.x

#python #python-3.x

Вопрос:

Проблема в том, что запуск exec() для переменной с именем именованного аргумента не работает при нормальной работе программы, но установка точки останова и выполнение рассматриваемой строки кода в том же месте, похоже, работают.

Воспроизведение проблемы следует:

 """ LEGACY CODE, CANNOT CHANGE vvvvvvvvvvv """ from collections import namedtuple class A_Object(namedtuple('A_object', 'parameter_a' ' parameter_b')): def __new__(cls, *args, **kwargs): init = super(A_Object, cls).__new__(cls, parameter_a=[], parameter_b=[]) return init """ ^^^^^^^^^^^ LEGACY CODE, CANNOT CHANGE """ def _remove_all_data(self): for field in self._fields: print("removing field:", field) # This does not work in the normal execution of the program, # but if you set a break point and execute the same command in the python console ( in Pycharm ) it works. exec('self = self._replace(=[])'.format(field)) return self def driver(): a = A_Object() a.parameter_a.append('a') a.parameter_a.append('b') a.parameter_a.append('c') a.parameter_b.append(1) a.parameter_b.append(2) a.parameter_b.append(3) # Try to remove all data from properties. a = a._remove_all_data() tmp = a._asdict() for k in tmp.keys(): for i in range(0, len(tmp[k])): print('<>[<>]='.format(k,i), tmp[k][i]) if __name__ == '__main__': driver() 

Этот минимально воспроизводимый пример покажет, что запуск программы приведет к выводу содержимого parameter_a и parameter_b (в этом проблема). Желаемым результатом будет parameter_a, а parameter_b будет пустым списком. Если вы поставили точку останова в exec(‘self = self._replace(=[])’.format(field)) строке и во время отладки откройте консоль python в pycharm и запустите эту строку кода « exec(‘self = self._replace(=[])’.format(field)) » в консоли. она очистит параметры_a и paramter_b (давая желаемый результат).

Комментарии:

1. вы не можете изменять локальные переменные с exec помощью / eval . Вы не должны использовать exec здесь в первую очередь

2. Но очевидно, что это не совсем тот случай, если я могу использовать exec для изменения локальных переменных в консоли python. И я согласен, что в этом случае лучше не использовать exec / eval.

3. Нет, вы не можете, в Python 3. Консоль отладчика отличается от обычной среды (на самом деле она уже используется exec …)

4. Спасибо, я этого не знал.

Ответ №1:

Вам это не нужно exec : если вам нужен аргумент ключевого слова с динамическим именем, используйте **kwargs синтаксис. Вы также можете заменить все поля одновременно, вместо того, чтобы вызывать _replace несколько раз в цикле:

 def _remove_all_data(self): return self._replace(**< f: [] for f in self._fields >) 

Комментарии:

1. Я забыл ** , когда я впервые устал kwargs проходить. Это решается для желаемого результата / результата. Спасибо. Прежде чем я отмечу это как ответ, знаете ли вы, почему exec ведет себя так странно, что не работает в этой программе?

2. @Theisen вы читали документацию для exec ? она предупреждает вас, что изменения локальных переменных не будут работать.

3. Это не странное поведение — это ожидаемое поведение. exec не изменяет значения локальных переменных, таких как self . Как советуют документы для exec функции: «Передайте явный словарь locals, если вам нужно увидеть влияние кода на locals после возврата функции exec()».

Источник

Читайте также:  Зачем нужен index php

Не получается определить функцию внутри ‘exec’

Вот такой вот пример работает по-разному в python2(2.7.3-r3) и python3(3.2.3-r2).

class A: def __init__(self): exec('f = lambda x: x') print(f(1)) a = A()

В python2 работает и возвращает 1. В python3:

Traceback (most recent call last): File "test.py", line 6, in a = A() File "test.py", line 4, in __init__ print(f(1)) NameError: global name 'f' is not defined

Хотелось бы понять почему. Никак не могу. Если определять не внутри метода класса — то вроде работает и в python3. А в чём конкретно разница? Ткните носом в ChangeLog — я такого нигде не видел. 🙁 хотя примерно разницу между python2/3 представляю.

P.S. зачем мне это понадобилось — не спрашивайте, перевожу один проектик с 2 на 3, а там вот такие вот костыли, от него так сразу не избавиться.

Это фича. Во первых, если не объявлена переменная, то она ищется в глобальном скоупе, а во вторых:

The default locals act as described for function locals() below: modifications to the default locals dictionary should not be attempted. Pass an explicit locals dictionary if you need to see effects of the code on locals after function exec() returns. 

Такие дела. Можешь сам подсовывать новую область видимости и брать оттуда результат.

 3 0 LOAD_GLOBAL 0 (exec) 3 LOAD_CONST 1 ('f = lambda x: x') 6 CALL_FUNCTION 1 9 POP_TOP 4 10 LOAD_GLOBAL 1 (print) 13 LOAD_GLOBAL 2 (f) 16 LOAD_CONST 2 (1) 19 CALL_FUNCTION 1 22 CALL_FUNCTION 1 25 POP_TOP 26 LOAD_CONST 0 (None) 29 RETURN_VALUE 
 3 0 LOAD_CONST 1 ('f = lambda x: x') 3 LOAD_CONST 0 (None) 6 DUP_TOP 7 EXEC_STMT 4 8 LOAD_NAME 0 (f) 11 LOAD_CONST 2 (1) 14 CALL_FUNCTION 1 17 PRINT_ITEM 18 PRINT_NEWLINE 19 LOAD_CONST 0 (None) 22 RETURN_VALUE 
>>> class A: . def __init__(self): . exec('f = lambda x: x', globals()) . print(f(1)) . >>> a = A() 1 

  1. Не используй exec.
  2. exec во 2-ом и 3-ем питонах это совершенно разные вещи.
  3. Во 2-м питоне exec(‘f = lambda x: x’) правильно записывается как exec ‘f = lambda x: x’.

А вообще по существу к комментарию xpahos’а можно добавить только два линка:

ei-grad ★★★★★ ( 12.04.13 05:01:25 MSK )
Последнее исправление: ei-grad 12.04.13 05:03:10 MSK (всего исправлений: 2)

Какие-то заумные ответы тут дают. Для простоты: Во 2 питоне exec это оператор, которые используют как локальное то пространство имен, в котором использованы сами. В тройке exec это функция, которая создает свое локальное пространство имен, в котором и определяется «f». Потому последующий код в методе __init__ в 3 питоне ничего про «f» знать не знает.

В тройке exec это функция, которая создает свое локальное пространство имен, в котором и определяется «f».

def boo(): exec('foo = "bar"') print(locals()) boo() 

Кстати, хороший вопрос для собеседования, обязательно воспользуюсь.

Читайте также:  Python инициализация массива значениями

А версия, господин преподаватель (надеюсь, хотя бы старших классов)?

Любая, начиная с 3.2. Скорее всего это распространяется и на 3.0/3.1. Если у тебя не работает, то интерпретатор с багом.

Очень интересно. А вот так почему?

class A: def __init__(self): exec('f = lambda x: x') g = locals()['f'] print(g(1)) a = A()
class A: def __init__(self): exec('f = lambda x: x') f = locals()['f'] print(f(1)) a = A()
Traceback (most recent call last): File "test.py", line 7, in a = A() File "test.py", line 4, in __init__ f = locals()['f'] KeyError: 'f' 

Собственно, этот финт ушами var = locals(‘varname’) мне помог, программу свою я починил. Понятно, что exec лучше не пользоваться, позже подумаю, как переписать этот код без него. Всем спасибо.

Тема решена, но вопросы остались 😉

такой вариант тоже. подойдёт. подумаю, что лучше. но скорее тупо избавлюсь от этого костыля

Так организована работа с таблицами символов. Если в коде есть объявление имени, то из exec с ним уже ничего не сделаешь.

def boo(): d = locals() exec('foo = "bar"', globals(), d) foo = d['foo'] print(foo) boo() 

Все потому, что locals это срез текущего скоупа и обновляется при каждом вызове.

вы используете в своём коде exec?

Генерация оберток, чтобы не потерять сигнатуру декорируемой функции. Конфиги. Точка входа для вызова из cli сложных команд.

Убедил :). Всё, пошёл к вам на собеседование.

Интересно. Тему новую создавать не хочется. Но ещё один интересный пример. Вот думаю, баг или фича. может, написать багрепорт pyyaml?

короче, pyyaml — библиотека для питона парсер yaml.

import yaml yaml.dump(lambda x,y,z: x+y+z)
"!!python/name:__main__.%3Clambda%3E ''\n"
Traceback (most recent call last): File "", line 1, in File "/usr/lib64/python3.2/site-packages/yaml/__init__.py", line 200, in dump return dump_all([data], stream, Dumper=Dumper, **kwds) File "/usr/lib64/python3.2/site-packages/yaml/__init__.py", line 188, in dump_all dumper.represent(data) File "/usr/lib64/python3.2/site-packages/yaml/representer.py", line 27, in represent self.serialize(node) File "/usr/lib64/python3.2/site-packages/yaml/serializer.py", line 54, in serialize self.serialize_node(node, None, None) File "/usr/lib64/python3.2/site-packages/yaml/serializer.py", line 90, in serialize_node style=node.style)) File "/usr/lib64/python3.2/site-packages/yaml/emitter.py", line 115, in emit self.state() File "/usr/lib64/python3.2/site-packages/yaml/emitter.py", line 228, in expect_document_root self.expect_node(root=True) File "/usr/lib64/python3.2/site-packages/yaml/emitter.py", line 242, in expect_node self.process_tag() File "/usr/lib64/python3.2/site-packages/yaml/emitter.py", line 489, in process_tag self.prepared_tag = self.prepare_tag(tag) File "/usr/lib64/python3.2/site-packages/yaml/emitter.py", line 607, in prepare_tag chunks.append('%%%02X' % ord(ch)) TypeError: ord() expected string of length 1, but int found 

как думаете, баг. всё-таки pyyaml должен поддерживаться веткой python3. практически я вряд ли данную комбинацию буду использовать (не очень читаемый «дамп» получается, потому смысла нет, pickle/shelve никто не отменял для этого если что)

Источник

Оцените статью