2012-06-01 14 views
10

Tôi đang bắt đầu thử nghiệm với các công cụ song song IPython và gặp sự cố. Tôi bắt đầu lên cơ python của tôi với:Các vấn đề về không gian tên Python với ipython song song

ipcluster start -n 3 

Sau đó, đoạn mã sau chạy tốt:

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 

lợi nhuận [42, 42, 42] như nó phải. Nhưng nếu tôi phá vỡ các mã vào file khác nhau: 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 

và hãy thử như sau:

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

tôi nhận được lỗi từ mỗi động cơ:

[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 

tôi don Không hiểu ... tại sao tôi không thể đặt hàm vào một tệp khác và nhập nó?

Trả lời

16

câu trả lời nhanh: trang trí chức năng của bạn với @interactive từ IPython.parallel.util [1] nếu bạn muốn nó được tiếp cận với không gian tên toàn cầu của động cơ:

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

Lời giải thích thực tế:

không gian tên người dùng IPython là về cơ bản mô-đun __main__. Đây là nơi mã được chạy khi bạn thực hiện execute('a = 5').

Nếu bạn định nghĩa một hàm tương tác, mô-đun của nó cũng là __main__:

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

Khi nào Công cụ unserializes một chức năng, nó làm như vậy trong không gian tên toàn cầu phù hợp với mô-đun của chức năng, vì vậy chức năng quy định tại __main__ trong khách hàng của bạn cũng được xác định trong __main__ trên Engine và do đó có quyền truy cập vào a.

Khi bạn đặt nó trong một file và import nó, sau đó các chức năng không còn gắn liền với __main__, nhưng các module dop:

 
from dop import dop 
dop.__module__ 
'dop' 

Tất cả các chức năng thông thường được định nghĩa trong module đó (lambdas bao gồm) sẽ có giá trị này, vì vậy khi chúng được giải nén trên Công cụ, không gian tên chung của chúng sẽ là của mô-đun dop, không phải__main__, do đó không thể truy cập 'a' của bạn.

Vì lý do này, IPython cung cấp trang trí đơn giản @interactive dẫn đến bất kỳ chức năng nào được giải nén như được định nghĩa trong __main__, bất kể vị trí thực sự được xác định.

Đối với một ví dụ về sự khác biệt, thực hiện việc này 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) 

Bây giờ, dop sẽ sử dụng 'a' từ các module dop, và idop sẽ sử dụng 'a' từ không gian tên động cơ của bạn.Sự khác biệt duy nhất giữa hai là các hàm được chuyển vào áp dụng được gói trong @interactive:

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

[1]: Trong IPython> = 0,13 (sắp phát hành), @interactive cũng có sẵn như là from IPython.parallel import interactive, nơi nó nên luôn luôn đã được.