2009-03-02 18 views
7

Tôi là một fan hâm mộ lớn của Python for...else syntax - thật đáng ngạc nhiên về mức độ thường xuyên áp dụng và cách hiệu quả để đơn giản hóa mã.Sử dụng cho ... else trong máy phát điện Python

Tuy nhiên, tôi đã không tìm ra một cách tốt đẹp để sử dụng nó trong một máy phát điện, ví dụ:

def iterate(i): 
    for value in i: 
     yield value 
    else: 
     print 'i is empty' 

Trong ví dụ trên, tôi muốn tuyên bố print được thực hiện chỉ khi i trống. Tuy nhiên, vì else chỉ tôn trọng breakreturn, nó luôn được thực hiện, bất kể độ dài i.

Nếu không thể sử dụng for...else theo cách này, cách tiếp cận tốt nhất cho điều này sao cho câu lệnh print chỉ được thực hiện khi không có gì được mang lại?

Trả lời

11

Bạn đang phá vỡ định nghĩa của một máy phát điện, mà phải ném một ngoại lệ StopIteration khi lặp đi lặp lại là đầy đủ (mà được tự động xử lý bởi một tuyên bố trở lại trong một chức năng máy phát điện)

Vì vậy:

def iterate(i): 
    for value in i: 
     yield value 
    return 

tốt nhất để cho mã gọi xử lý trường hợp của một iterator trống:

count = 0 
for value in iterate(range([])): 
    print value 
    count += 1 
else: 
    if count == 0: 
     print "list was empty" 

có thể là một cách sạch hơn làm ở trên, nhưng đó phải làm việc tốt, và không rơi vào bất kỳ cái bẫy chung 'xử lý một vòng lặp như một danh sách' dưới đây.

+3

trả về được ngụ ý ở cuối máy phát. Không cần phải bao gồm nó. – recursive

+0

Tôi đã nghĩ vậy, nhưng tôi nghĩ tôi sẽ để nó rõ ràng ở đây. – Triptych

+2

+1: "in i trống" là vấn đề của người khác, không phải của máy phát. –

-2

Điều gì sẽ đơn giản nếu có?

def iterate(i): 
    if len(i) == 0: print 'i is empty' 
    else: 
     for value in i: 
      yield value 
+0

Các đối số tôi có thể không có một len ​​được xác định, vì vậy đây là vấn đề. – Kiv

+0

Cùng một vấn đề như câu trả lời của đệ quy, nhiều hay ít. – Triptych

5

Có một số cách để thực hiện việc này. Bạn luôn có thể sử dụng Iterator trực tiếp:

def iterate(i): 
    try: 
     i_iter = iter(i) 
     next = i_iter.next() 
    except StopIteration: 
     print 'i is empty' 
     return 

    while True: 
     yield next 
     next = i_iter.next() 

Nhưng nếu bạn biết thêm về những gì mong đợi từ đối số i, bạn có thể ngắn gọn hơn:

def iterate(i): 
    if i: # or if len(i) == 0 
     for next in i: 
      yield next 
    else: 
     print 'i is empty' 
     raise StopIteration() 
0

Nếu nó không thể sử dụng cho ... khác theo cách này, cách tiếp cận tốt nhất cho điều này để báo cáo in chỉ được thực hiện khi không có gì được mang lại?

tối đa tôi có thể nghĩ ra:

 

>>> empty = True 
>>> for i in [1,2]: 
...  empty = False 
... if empty: 
...  print 'empty' 
... 
>>> 
>>> 
>>> empty = True 
>>> for i in []: 
...  empty = False 
... if empty: 
... print 'empty' 
... 
empty 
>>> 
 
3

Tổng hợp một số các câu trả lời trước đó, nó có thể được giải quyết như thế này:

def iterate(i): 
    empty = True 
    for value in i: 
     yield value 
     empty = False 

    if empty: 
     print "empty" 

do đó thực sự là không có "khác "khoản có liên quan.

3

Khi bạn lưu ý, for..else chỉ phát hiện break. Vì vậy, nó chỉ áp dụng khi bạn tìm kiếm một cái gì đó và sau đó dừng lại.

Không áp dụng cho mục đích của bạn không phải vì nó là máy phát điện, nhưng vì bạn muốn xử lý tất cả các thành phần, mà không dừng lại (vì bạn muốn mang lại tất cả, nhưng đó không phải là điểm).

Vì vậy, máy phát điện hay không, bạn thực sự cần một boolean, như trong giải pháp của Ber.