2014-12-04 3 views
1

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

# script.py 
import IPython as ip 

def Reload(): 
    execfile('routines.py', {}, globals()) 

if __name__ == "__main__": 
    ip.embed() 

Предположим, файл routines.py как это:

# routines.py 
def f(): 
    print 'help me please.' 
def g(): 
    f() 

Теперь, если я бегу script.py сценарий, я буду входа в интерактивную оболочку. Если я печатаю следующее, мой вызов г() работает:

execfile('routines.py') 
g() 

Однако, если я печатаю следующее, вызов г() не:

Reload() 
g() 

Я получаю сообщение об ошибке говоря, что «глобальное имя f не определено»., хотя я все еще могу видеть, что f и g находятся на выходе, когда я ввожу globals() в интерактивную оболочку.

В чем разница этих двух?

UPDATE:

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

Если изменить script.py на:

# script.py 
import IPython as ip 

def Reload(): 
    execfile('routines.py') 

if __name__ == "__main__": 
    ip.embed() 

И изменить routines.py на:

# routines.py 

global f 
global g 

def f(): 
    print 'help me please.' 
def g(): 
    f() 

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

UPDATE 2:

кажется, что проблема не зависит от IPython. С первой версией routines.py если я запустить оболочку Python, и введите следующую команду вручную:

def Reload(): 
    execfile('routines.py', {}, globals()) 

g() 

призыв к г() также терпит неудачу. Но следующие работы:

execfile('routines.py') 
g() 
+1

Почему вы используете 'execfile'? Просто импортируйте модуль: 'from routines import *'. – Bakuriu

+0

Извините, почему-то я не могу этого сделать. Я также ошибся в описании проблемы, и теперь я ее обновил. Спасибо! – shaoyl85

ответ

0

Как @Bakuriu сказал, импорт очень предпочтителен. Игнорируя это, вы хотите получить

def Reload(): 
    execfile('routines.py', globals()) 

Проясните ваш пример, чтобы показать, почему он не работает.

# Setup the namespace to use for execfile 
global_dict = {} 
local_dict = globals() 
execfile('routines.py', global_dict, local_dict) 
g() # raises NameError 

Поскольку вы передаете два разных dicts к execfile, файл выполняется, как если бы это было в определении класса (from the docs). Это означает, что ваши функции определены в local_dict, но не global_dict.

Когда вы звоните g(), он выполняется с использованием глобальных символов global_dict и свежего пустого местного dict.Поскольку ни global_dict, ни новые местные жители не содержат f, мы получаем ошибку имени. Вместо этого, вызывая execfile('routines.py', globals()), мы используем global_dict = globals() и local_dict = globals(), поэтому f определяется в глобальном масштабе g.

EDIT:

Вы заметили, что local_dict имеет как f и g, но global_dict не во втором примере. Определение любой переменной без явной маркировки ее global всегда будет делать локальную переменную, это также относится к модулям! Так получилось, что обычно модуль имеет locals() == globals(); однако мы нарушили этот стандарт, используя различные локальные и глобальные дикты. Это то, что я имел в виду, когда я сказал, что «файл выполнен, как если бы он был в определении класса».

+0

Замечательно! Спасибо за ответ! – shaoyl85

+0

На самом деле, если я запустил второй сегмент кода, который вы положили, я вижу f и g в local_dict, но не в global_dict. Можете ли вы объяснить, почему? – shaoyl85

+0

@ shaoyl85 см. Мое редактирование, надеюсь, это очистит его. Если у вас больше вопросов, вы можете задать вопрос. – kalhartt

Смежные вопросы