Ответ 1
Быстрый ответ: украсьте свою функцию с помощью @interactive
от IPython.parallel.util
[1], если вы хотите, чтобы у нее был доступ к глобальному пространству имен движка:
from IPython.parallel.util import interactive f = interactive(lambda x: a+b+x) ack = dview.apply(f, x)
Фактическое объяснение:
пространство имен пользователей IPython по существу является модулем __main__
. Здесь код запускается, когда вы выполняете execute('a = 5')
.
Если вы определяете функцию в интерактивном режиме, ее модуль также __main__
:
lam = lambda x: a+b+x lam.__module__ '__main__'
Когда Engine не выполняет инициализацию функции, он делает это в соответствующем глобальном пространстве имен для функционального модуля, поэтому функции, определенные в __main__
в вашем клиенте, также определены в __main__
в Engine и, следовательно, имеют доступ к a
.
Как только вы поместите его в файл и импортируете, функции больше не привязаны к __main__
, а модуль dop
:
from dop import dop dop.__module__ 'dop'
Все функции, условно определенные в этом модуле (включая lambdas), будут иметь это значение, поэтому, когда они распаковываются в Engine, их глобальное пространство имен будет принадлежать модулю dop
, а не __main__
, поэтому ваш 'a' недоступен.
По этой причине IPython предоставляет простой декодер @interactive
, который приводит к распаковке любой функции, как если бы она была определена в __main__
, независимо от того, где фактически определена функция.
Для примера разницы возьмите этот dop.py
:
from IPython.parallel import Client from IPython.parallel.util import interactive a = 1 def dop(x): rc = Client() dview = rc[:] dview['a'] = 5 f = lambda x: a+x return dview.apply_sync(f, x) def idop(x): rc = Client() dview = rc[:] dview['a'] = 5 f = interactive(lambda x: a+x) return dview.apply_sync(f, x)
Теперь dop
будет использовать 'a' из модуля dop, а idop
будет использовать 'a' из ваших пространств имен движков. Единственное различие между ними состоит в том, что функция, переданная для применения, заверяется в @interactive
:
from dop import dop, idop print dop(5) # 6 print idop(5) # 10
[1]: В IPython >= 0.13 (предстоящий выпуск) @interactive
также доступен как from IPython.parallel import interactive
, где он всегда должен был быть.