#python #python-2.7 #multiprocessing #nameerror
#python #python-2.7 #многопроцессорная обработка #ошибка имени
Вопрос:
У меня есть основной процесс, который использует execfile и запускает скрипт в дочернем процессе. Это работает нормально, если скрипт не находится в другом каталоге — тогда все ломается.
Это в mainprocess.py
:
from multiprocessing import Process
m = "subdir\test.py"
if __name__ == '__main__':
p = Process(target = execfile, args = (m,))
p.start()
Затем в подкаталоге, точно названном subdir, у меня есть test.py
import time
def foo():
print time.time()
foo()
При запуске mainprocess.py
я получаю сообщение об ошибке:
NameError: global name 'time' is not defined
но проблема не ограничивается именами модулей — иногда я получаю ошибку в имени функции в других фрагментах кода.
Я пытался импортировать time в mainprocess.py
, а также внутри if
инструкции там, но ни то, ни другое не дало никакого эффекта.
Один из способов избежать ошибки (я этого не пробовал) — скопировать test.py
в родительский каталог и вставить строку в файл, чтобы os.chdir
вернуться в исходный каталог. Однако это кажется довольно неаккуратным.
Итак, что происходит?
Комментарии:
1. Почему бы не использовать
subprocess
модуль для этого?
Ответ №1:
Решение состоит в том, чтобы изменить инициализацию вашего процесса:
p = Process(target=execfile, args=(m, {}))
Честно говоря, я не совсем уверен, почему это работает. Я знаю, что это как-то связано с тем, в какой словарь (локальные или глобальные) добавляется импорт времени. Кажется, что когда ваш импорт выполняется в test.py это обрабатывается как локальная переменная, потому что работает следующее:
import time # no foo() anymore
print(time.time()) # the call to time.time() is in the same scope as the import
Однако также работает следующее:
import time
def foo():
global time
print(time.time())
foo()
Этот второй пример показывает мне, что импорт по-прежнему присваивается какому-то виду глобального пространства имен, я просто не знаю, как и почему.
Если вы вызываете execfile() обычным способом, а не в подпроцессе, все выполняется нормально, и фактически, вы можете использовать модуль time в любом месте после вызова execfile() в вашем основном процессе, потому что время было перенесено в то же пространство имен. Я думаю, что, поскольку вы запускаете его в подпроцессе, нет пространства имен на уровне модуля, которому должен быть назначен импорт (execfile не создает объект модуля при вызове). Я думаю, что когда мы добавляем пустой словарь к вызову execfile, мы добавляем аргумент глобального словаря, таким образом предоставляя механизму импорта глобальное пространство имен для присвоения имени time.
Некоторые ссылки для фона:
1) Страница руководства по пространствам имен и области действия — сначала посмотрите здесь объяснения встроенных, глобальных и локальных пространств имен