Поведение Python exec () отличается в зависимости от того, откуда он вызывается - PullRequest
0 голосов
/ 26 августа 2010

У меня есть скрипт Python 'runme.py', который я пытаюсь выполнить из 'callerX.py' ниже. Я использую exec (open (filename) .read ()) для выполнения этой задачи. Выполняемый скрипт содержит простой класс, который пытается вызвать функцию time () как из глобального пространства имен, так и внутри функции.

Во всех приведенных ниже примерах мы выполняем следующий файл, используя exec ():


# runme.py
# this code is being exec()'d by the stand-alone examples 1-3 below:
from time import *

class MyClass():
    def main(self):
        print("Local tracepoint 1")
        t = time()
        print("Local tracepoint 2")

mc = MyClass()
print("Tracepoint 1")
gt = time()
print("Tracepoint 2")
mc.main()
print("Tracepoint 3")


caller1.py: (это работает правильно, функция 'time' может использоваться в MyClass.main ())

<code>
print("Run from main scope:")
exec(open("runme.py").read())

caller2.py: (это не работает, происходит сбой с исключением «NameError: глобальное имя« время »не определено» внутри MyClass.main ())
<code>
def Run():
    exec(open("runme.py").read())</p>

<p>print("Run from function:")
Run()

caller3.py: (это работает правильно, оба exec () работают без исключений)
<code>
def Run():
    exec(open("runme.py").read())</p>

<p>print("Run from main scope:")
exec(open("runme.py").read())</p>

<p>print("Run from function:")
Run()

Обратите внимание, что в приведенных выше примерах вызовы функции time () в глобальном пространстве имен runme.py всегда работают, а вызовы функции time () из MyClass.main () только иногда работают, в зависимости от того, был ли файл runme.py exec () 'd изнутри функции.

Если мы вызываем exec () извне функции (caller1.py), это работает. Если мы вызываем exec () из функции (caller2.py), она завершается с исключением. Если мы вызываем exec () извне функции, а затем изнутри функции (caller3.py), оба вызова exec () запускаются без исключения.

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

Ответы [ 2 ]

0 голосов
/ 27 августа 2010

Вот идея: не используйте exec. По сути, каждый раз, когда я видел, как кто-то использует exec или eval, это потому, что он не знает, что лучший способ сделать то же самое уже существует; это костыль, который мешает писать динамический код, а не способ написать код, который как-то более динамичен.

0 голосов
/ 27 августа 2010

Это, вероятно, связано с тем, как работает 'из x import *'.Если вы вызываете это из верхнего уровня, он импортируется в globals () для всего модуля.

Однако, если вы вызываете это внутри функции, он импортируется только в locals () - вфункция.Exec () вычисляется внутри функции в caller2;поэтому import * не попадает в globals (), а «внутренняя» основная функция его не видит.

Кстати: интересно, если вы попробуете код, подобный этому:

def run():
    from time import *
    def test():
        print time()
    test()
run()

Вы получите исключение: SyntaxError: импорт * не разрешен в функции 'run', поскольку она содержит вложенную функцию со свободными переменными

Но это именно то, что вы делаете с exec, нокак-то удивительно пробирается.

Однако - учитывая другой ответ здесь - почему бы вам не использовать что-то другое вместо этого?Посмотрите документацию к модулю 'imp' - в частности, функции find_module и load_module.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...