2012-06-01 9 views
10

Zaczynam eksperymentować z narzędziami równoległymi IPython i mam problem. Zacznę moje silniki Pythona z:Problemy z przestrzenią nazw w języku Python z ipython równolegle

ipcluster start -n 3 

Następnie dodaje kod działa poprawnie:

from IPython.parallel import Client 

def dop(x): 
    rc = Client() 
    dview = rc[:] 
    dview.block=True 
    dview.execute('a = 5') 
    dview['b'] = 10 
    ack = dview.apply(lambda x: a+b+x, x) 
    return ack 

ack = dop(27) 
print ack 

powraca [42, 42, 42], jak powinien. Ale jeśli złamię kod do różnych plików: dop.py:

from IPython.parallel import Client 

def dop(x): 
    rc = Client() 
    dview = rc[:] 
    dview.block=True 
    dview.execute('a = 5') 
    dview['b'] = 10 
    print dview['a'] 
    ack = dview.apply(lambda x: a+b+x, x) 
    return ack 

i spróbuj wykonać następujące czynności:

from dop import dop 
ack = dop(27) 
print ack 

pojawiają się błędy z każdego silnika:

[0:apply]: NameError: global name 'a' is not defined 
[1:apply]: NameError: global name 'a' is not defined 
[2:apply]: NameError: global name 'a' is not defined 

I don Nie rozumiem ... dlaczego nie mogę umieścić tej funkcji w innym pliku i zaimportować?

Odpowiedz

16

Szybka odpowiedź: ozdobić swoją funkcję z @interactive od IPython.parallel.util [1], jeśli chcesz, aby mieć dostęp do globalnej przestrzeni nazw silnika:

 
from IPython.parallel.util import interactive 
f = interactive(lambda x: a+b+x) 
ack = dview.apply(f, x) 

Rzeczywiste wyjaśnienie:

przestrzeń nazw użytkownika ipython jest zasadniczo moduł __main__. Tutaj kod jest uruchamiany, gdy wykonujesz execute('a = 5').

Jeśli zdefiniować funkcję interaktywnego, jego moduł jest również __main__:

 
lam = lambda x: a+b+x 
lam.__module__ 
'__main__' 

gdy silnik unserializes funkcję, robi to w odpowiednim globalnej przestrzeni nazw dla modułu funkcyjnego, więc funkcje zdefiniowane w __main__ w twój klient jest również zdefiniowany w __main__ na silniku, a tym samym ma dostęp do a.

Po umieścić go w pliku i zaimportować go, a następnie funkcje nie są już przypisane do __main__, ale moduł dop:

 
from dop import dop 
dop.__module__ 
'dop' 

Wszystkie funkcje tradycyjnie zdefiniowane w tym module (lambdas zestawie) będą musiały ta wartość, więc gdy zostaną rozpakowane w Silniku, ich globalna przestrzeń nazw będzie taka sama, jak w przypadku modułu dop, więc twoje "a" nie będzie dostępne.

Z tego powodu IPython udostępnia prosty dekorator @interactive, który powoduje rozpakowanie dowolnej funkcji, jak gdyby została zdefiniowana w __main__, niezależnie od tego, gdzie funkcja jest faktycznie zdefiniowana.

Na przykład różnicy, weź to 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) 

Teraz dop użyje 'a' z modułu dop, a idop użyje 'a' od nazw silnika.Jedyną różnicą pomiędzy nimi jest to funkcja przekazywane do zastosowania owinięta @interactive:

 
from dop import dop, idop 
print dop(5) # 6 
print idop(5) # 10 

[1]: w ipython> = 0,13 (kolejne wydanie) @interactive jest również dostępny jako from IPython.parallel import interactive, gdzie powinny zawsze byli.

Powiązane problemy