2011-08-18 12 views
27

Tôi đang sử dụng máy phát điện để thực hiện tìm kiếm trong danh sách như ví dụ này đơn giản:Làm thế nào tôi có thể nhận được một trình tạo Python để trả về None chứ không phải StopIteration?

>>> a = [1,2,3,4] 
>>> (i for i, v in enumerate(a) if v == 4).next() 
3 

(Chỉ cần khung ví dụ một chút, tôi đang sử dụng danh sách còn rất nhiều so với một ở trên, và các mục là một phức tạp hơn một chút so với int. Tôi làm theo cách này để toàn bộ danh sách sẽ không được duyệt qua mỗi khi tôi tìm kiếm chúng)

Bây giờ nếu thay vào đó, hãy đổi thành i == 666, nó sẽ trả lại StopIteration vì nó có thể ' t tìm thấy bất kỳ mục nhập 666 nào trong a.

Làm cách nào để tôi trả lại None? Tôi có thể tất nhiên quấn nó trong một điều khoản try ... except, nhưng là có một cách nhiều hơn pythonic để làm điều đó?

+0

Tôi có thể hỏi lý do tại sao bạn đang sử dụng máy phát điện để tìm kiếm những thứ? –

+0

Bạn mong đợi điều gì sẽ xảy ra nếu bạn tìm kiếm thứ gì đó mà bạn đã vượt qua? Tại sao không chỉ sử dụng nhiều hơn 'pythonic' cách như 'if i in a: ...'? –

+0

@Manny D, 'if i in a' không giúp ích nếu bạn muốn lấy chỉ mục của mục tìm thấy. – senderle

Trả lời

70

Nếu bạn đang sử dụng Python 2.6+ bạn nên sử dụng next built-in chức năng, không phải là phương pháp next (được thay thế bằng __next__ trong 3.x). Các next built-in có một đối số mặc định tùy chọn để quay trở lại nếu iterator là kiệt sức, thay vì nâng StopIteration:

next((i for i, v in enumerate(a) if i == 666), None) 
+1

+1, đây là cách tốt nhất để làm điều này. – senderle

+0

Tôi không biết chức năng tích hợp đã thay đổi. Điều đó làm cho nó dễ dàng hơn rất nhiều – c00kiemonster

7

Bạn có thể chuỗi các máy phát điện với (Không,):

from itertools import chain 
a = [1,2,3,4] 
print chain((i for i, v in enumerate(a) if v == 6), (None,)).next() 

nhưng tôi nghĩ a.index (2) sẽ không đi qua danh sách đầy đủ, khi 2 được tìm thấy, việc tìm kiếm kết thúc. bạn có thể kiểm tra điều này:

>>> timeit.timeit("a.index(0)", "a=range(10)") 
0.19335955439601094 
>>> timeit.timeit("a.index(99)", "a=range(100)") 
2.1938486138533335 
+1

Điều chuỗi là rất thông minh, không nghĩ về điều đó. Có 'index()' không phải là xấu, nhưng trong trường hợp thực sự của tôi, tôi không thể thực sự sử dụng nó vì các mục danh sách là các đối tượng chứ không phải là các biến. EDIT: Tôi đang so sánh các thuộc tính đối tượng và các công cụ thú vị khác thay vì chỉ tìm kiếm đối tượng. – c00kiemonster

+1

Xin lỗi để nói điều này, nhưng đây là một giải pháp quá phức tạp. Hàm dựng sẵn 'next' đã cung cấp chức năng này một cách rõ ràng. @ c00kiemonster, tôi nghĩ bạn nên sử dụng (và chấp nhận) [câu trả lời của zeekay] (http://stackoverflow.com/questions/7102050/how-can-i-get-a-python-generator-to-return-none-rather -an-stopiteration/7102204 # 7102204). – senderle

+0

Đừng lo, cách tốt nhất để tìm ra những thứ mới hơn trong Python nếu không có gì khác ... – c00kiemonster