2012-09-28 14 views
16

Tôi không thể hiểu phương thức send. Tôi hiểu rằng nó được sử dụng để vận hành máy phát điện. Nhưng cú pháp là ở đây: generator.send(value).Python 3: gửi phương pháp máy phát điện

Tôi bằng cách nào đó không thể hiểu tại sao giá trị sẽ trở thành kết quả của biểu thức yield hiện tại. Tôi đã chuẩn bị một ví dụ:

def gen(): 
    for i in range(10): 
     X = yield i 
     if X == 'stop': 
      break 
     print("Inside the function " + str(X)) 

m = gen() 
print("1 Outside the function " + str(next(m)) + '\n') 
print("2 Outside the function " + str(next(m)) + '\n') 
print("3 Outside the function " + str(next(m)) + '\n') 
print("4 Outside the function " + str(next(m)) + '\n') 
print('\n') 
print("Outside the function " + str(m.send(None)) + '\n') # Start generator 
print("Outside the function " + str(m.send(77)) + '\n') 
print("Outside the function " + str(m.send(88)) + '\n') 
#print("Outside the function " + str(m.send('stop')) + '\n') 
print("Outside the function " + str(m.send(99)) + '\n') 
print("Outside the function " + str(m.send(None)) + '\n') 

Kết quả là:

1 Outside the function 0 

Inside the function None 
2 Outside the function 1 

Inside the function None 
3 Outside the function 2 

Inside the function None 
4 Outside the function 3 



Inside the function None 
Outside the function 4 

Inside the function 77 
Outside the function 5 

Inside the function 88 
Outside the function 6 

Inside the function 99 
Outside the function 7 

Inside the function None 
Outside the function 8 

Vâng, nói thẳng thắn, đó là đáng ngạc nhiên cho tôi.

  1. Trong các tài liệu chúng ta có thể đọc thấy rằng khi một tuyên bố yield được thực thi, trạng thái của máy phát điện là đông lạnh và giá trị của expression_list được trả lại cho người gọi next ‘s. Vâng, dường như điều đó không xảy ra. Tại sao chúng ta có thể thực hiện câu lệnh if và hàm print bên trong gen().
  2. Làm cách nào để hiểu lý do tại sao X bên trong và bên ngoài chức năng khác? Ok. Giả sử rằng send(77) truyền 77 thành m. Vâng, biểu thức yield trở thành 77. Sau đó, X = yield i là gì? Và làm thế nào 77 bên trong hàm chuyển đổi thành 5 khi xảy ra bên ngoài?
  3. Tại sao chuỗi kết quả đầu tiên không phản ánh bất kỳ thứ gì đang diễn ra bên trong trình tạo?

Dù sao, bạn có thể nhận xét bằng cách nào đó về những tuyên bố sendyield này không?

Trả lời

40

Khi bạn sử dụng send và biểu hiện yield trong máy phát điện, bạn đang coi nó là một coroutine; một chuỗi thực thi riêng biệt có thể chạy tuần tự xen kẽ nhưng không song song với người gọi của nó.

Khi người gọi thực hiện R = m.send(a), nó đặt đối tượng a vào khe nhập của trình tạo, chuyển điều khiển đến máy phát và đợi phản hồi. Trình tạo nhận đối tượng a là kết quả của X = yield i và chạy cho đến khi nó đạt đến biểu thức yield khác ví dụ: Y = yield j. Sau đó, nó đặt j vào vị trí đầu ra của nó, chuyển điều khiển trở lại người gọi và chờ cho đến khi nó được tiếp tục lại. Người gọi nhận được j là kết quả của R = m.send(a) và chạy cho đến khi nó chạm vào tuyên bố S = m.send(b) khác, v.v.

R = next(m) chỉ giống như R = m.send(None); nó đặt None vào khe đầu vào của máy phát điện, vì vậy nếu máy phát điện kiểm tra kết quả của X = yield i thì X sẽ là None.

Như một phép ẩn dụ, hãy xem xét một dumb waiter:

Dumb waiter

Khi máy chủ nhận được một đơn đặt hàng từ khách hàng, họ đặt pad trong người phục vụ câm, send nó vào bếp, và chờ đợi của hatch cho món ăn:

R = kitchen.send("Ham omelette, side salad") 

Đầu bếp (của những người được chờ đợi bởi sự nở) nhặt trật tự, chuẩn bị các món ăn, yield là nó đến nhà hàng, và chờ đợi cho thứ tự tiếp theo:

next_order = yield [HamOmelette(), SideSalad()] 

Máy chủ (những người được chờ đợi bởi sự nở) có các món ăn cho khách hàng và lợi nhuận với trật tự khác vv

Bởi vì cả hai máy chủ và đầu bếp chờ đợi bởi sự nở sau send ing một trật tự hoặc yield nhập một món ăn, chỉ có một người làm bất cứ điều gì tại bất kỳ thời điểm nào, tức là quy trình này được tạo thành một luồng. Cả hai bên đều có thể sử dụng dòng điều khiển bình thường, vì máy móc phát điện (người phục vụ câm) sẽ quan tâm đến việc thực hiện xen kẽ.

+0

nó chạy đồng thời chỉ không song song. – jfs

+0

@ J.F.Sebastian Tôi nghĩ "đồng thời" có nghĩa là song song? – ecatmur

+2

trong lập trình "song song" ngụ ý "đồng thời" nhưng ngược lại nói chung là không đúng sự thật. [Sự khác biệt giữa lập trình đồng thời và lập trình song song] (http://stackoverflow.com/q/1897993/4279) – jfs

4
def gen(): 
    i = 1 
    while True: 
     i += 1 
     x = yield i 
     print(x) 

m = gen() 
next(m) 
next(m) 
m.send(4) 

kết quả

None 
4 

nhìn vào mã đơn giản hơn ở trên.
Tôi nghĩ rằng điều dẫn đến sự nhầm lẫn của bạn là 'x = yield i' statment, statment này không nói giá trị được chấp nhận từ phương thức send() được xác định cho i sau đó tôi đã xác nhận x. Thay vào đó, giá trị i được trả về bởi tỷ lệ sản lượng cho máy phát, x được xác nhận bởi phương thức send() method.One thực hiện hai điều cùng một lúc.

9

Phần khó hiểu nhất nên là dòng này X = yield i, đặc biệt khi bạn gọi send() trên máy phát. Trên thực tế điều duy nhất bạn cần biết là:

ở mức từ vựng: next() bằng send(None)

ở mức độ phiên dịch: X = yield i bằng xuống dưới dòng (TRÌNH TỰ VẤN ĐỀ) :

yield i 
# won't continue until next() or send() is called 
# and this is also the entry point of next() or send() 
X = the_input_of_send 

và, 2 dòng nhận xét là lý do chính xác, tại sao chúng ta cần phải ca ll send(None) cho lần đầu tiên, bởi vì các máy phát điện sẽ trở lại i (năng suất i) trước gán giá trị để X

+0

Trả lời tuyệt vời! Lời giải thích đơn giản và dễ dàng. Bạn đã xác định rất rõ điểm yếu 'X = yield i'. sẽ tăng 10 lần –