2011-01-19 31 views
110

Tôi có một chức năng máy phát điện như sau:cách chọn chỉ một mục từ máy phát (trong python)?

def myfunct(): 
    ... 
    yield result 

Cách thông thường để gọi chức năng này sẽ là:

for r in myfunct(): 
    dostuff(r) 

Câu hỏi của tôi, là có một cách để có được chỉ là một phần tử từ các máy phát điện bất cứ khi nào tôi thích? Ví dụ, tôi muốn làm một cái gì đó như:

while True: 
    ... 
    if something: 
     my_element = pick_just_one_element(myfunct()) 
     dostuff(my_element) 
    ... 

Trả lời

161

Tạo một máy phát điện sử dụng

g = myfunct() 

Mỗi lần bạn muốn một mục, sử dụng

g.next() 

hoặc

next(g) 

Nếu máy phát điện thoát, nó sẽ nâng cao StopIteration. Bạn có thể bắt ngoại lệ này nếu cần thiết, hoặc sử dụng các lập luận default để next():

next(g, default_value) 
+3

Lưu ý, nó sẽ chỉ tăng StopIteration khi bạn cố gắng sử dụng g.next() sau khi mục cuối cùng trong g đã được cung cấp. – Wilduck

+15

'next (gen, default)' cũng có thể được sử dụng để tránh ngoại lệ 'StopIteration'. Ví dụ 'next (g, None)' cho một bộ tạo chuỗi sẽ tạo ra một chuỗi hoặc None sau khi kết thúc quá trình lặp. – Attila

+4

trong Python 3000, next() là __next __() –

-1

Tôi tin rằng cách duy nhất là để có được một danh sách từ iterator sau đó được những yếu tố mà bạn muốn từ danh sách đó.

l = list(myfunct()) 
l[4] 
+0

Câu trả lời của Sven có lẽ tốt hơn, nhưng tôi sẽ chỉ để lại điều này ở đây trong trường hợp nó phù hợp hơn với nhu cầu của bạn. – keegan3d

+22

Hãy chắc chắn rằng bạn có một máy phát điện hữu hạn trước khi thực hiện việc này. – Seth

+5

Xin lỗi, điều này có độ phức tạp của độ dài của trình lặp, trong khi vấn đề rõ ràng là O (1). –

2

Tôi không tin rằng có một cách thuận tiện để truy lục giá trị tùy ý từ trình tạo. Máy phát sẽ cung cấp một phương thức next() để đi qua chính nó, nhưng trình tự đầy đủ không được tạo ra ngay lập tức để tiết kiệm bộ nhớ. Đó là sự khác biệt chức năng giữa một máy phát điện và một danh sách.

0
generator = myfunct() 
while True: 
    my_element = generator.next() 

chắc chắn để bắt ngoại lệ ném sau khi yếu tố cuối cùng được lấy

+0

Không hợp lệ cho Python 3, xem [answer by kxr] xuất sắc (http://stackoverflow.com/a/35370041/260122). – clacke

12

Đối chọn chỉ là một yếu tố của việc sử dụng máy phát điện break trong một tuyên bố for, hoặc list(itertools.islice(gen, 1))

Theo ví dụ của bạn (rác) bạn có thể làm như:

while True: 
    ... 
    if something: 
     for my_element in myfunct(): 
      dostuff(my_element) 
      break 
     else: 
      do_generator_empty() 

Nếu bạn muốn "nhận jus t một phần tử từ [một lần tạo ra] máy phát điện bất cứ khi nào tôi thích "(Tôi cho rằng 50% thats ý định ban đầu, và mục đích phổ biến nhất) thì:

gen = myfunct() 
while True: 
    ... 
    if something: 
     for my_element in gen: 
      dostuff(my_element) 
      break 
     else: 
      do_generator_empty() 

Bằng cách này sử dụng rõ ràng của generator.next() có thể tránh và xử lý kết thúc đầu vào không yêu cầu (khó hiểu) StopIteration xử lý ngoại lệ hoặc so sánh giá trị mặc định bổ sung.

Phần else: của for chỉ cần thiết nếu bạn muốn thực hiện điều gì đó đặc biệt trong trường hợp máy phát cuối.

Lưu ý về next()/.next():

Trong Python3 phương pháp .next() được đổi tên thành .__next__() cho lý do chính đáng: được coi là ở mức độ thấp của nó (PEP 3114). Trước Python 2.6 hàm dựng sẵn next() không tồn tại. Và thậm chí nó còn được thảo luận để di chuyển next() đến mô-đun operator (điều này sẽ khôn ngoan), vì nhu cầu hiếm hoi và lạm phát có vấn đề về tên dựng sẵn của nó.

Sử dụng next() mà không mặc định vẫn là thực hành cấp độ rất thấp - ném mã khó hiểu StopIteration giống như một bu lông ra khỏi màu xanh trong mã ứng dụng thông thường công khai. Và sử dụng next() với nội dung gửi mặc định - tốt nhất nên là tùy chọn duy nhất cho số next() trực tiếp trong builtins - bị giới hạn và thường đưa ra lý do cho logic/không thể đọc được phi logic.

Dòng dưới cùng: Sử dụng tiếp theo() phải rất hiếm - như sử dụng các hàm của mô-đun operator. Sử dụng for x in iterator, islice, list(iterator) và các chức năng khác chấp nhận một trình lặp liên tục là cách tự nhiên của việc sử dụng trình vòng lặp ở cấp ứng dụng - và hoàn toàn có thể. next() là cấp độ thấp, một khái niệm phụ, không rõ ràng - như câu hỏi của chủ đề này cho thấy. Trong khi ví dụ: sử dụng break trong for là thông thường.

+0

Đây là cách quá nhiều công việc cho chỉ nhận được các yếu tố đầu tiên của một kết quả danh sách. Thường thì tôi không cần nó để được lười biếng nhưng không có một sự lựa chọn trong py3. Không có cái gì giống như 'mySeq.head'? – javadba

Các vấn đề liên quan