2010-02-20 35 views
36

Có cách viết ngắn gọn hơn về cú pháp sau đây không?Lấy mục thứ n của máy phát điện bằng Python

gen = (i for i in xrange(10)) 
index = 5 
for i, v in enumerate(gen): 
    if i is index: 
     return v 

Có vẻ như gần như tự nhiên rằng trình tạo nên có biểu thức gen[index], hoạt động như một danh sách, nhưng có chức năng giống với mã ở trên.

+8

Bạn không muốn 'is' trong tình huống này (hoặc nhiều tình huống ở tất cả). 'is' là để so sánh danh tính, không bình đẳng. Bạn muốn '=='. Điều này có thể sẽ làm việc trong trường hợp này, nhưng chỉ bởi sự trùng hợp và chi tiết thực hiện. –

+1

Vì tôi đang sử dụng các số nguyên, làm thế nào nó có thể không hoạt động? Thậm chí có thực hành tốt để mong đợi đối tượng 'index' thực thi' __eq__' trong các trường hợp như thế này không? (Đây là việc thoát khỏi chủ đề ...) –

+2

Hãy thử '1000 là 500 + 500', nó sẽ (có thể) là' Sai'. Xem, ví dụ: http://stackoverflow.com/questions/306313/python-is-operator-behaves-unexpectedly-with-integers –

Trả lời

35

một phương pháp sẽ được sử dụng itertools.islice

>>> next(itertools.islice(xrange(10), 5, 5 + 1)) 
5 
+3

Tôi hoàn toàn không biết về hàm 'next()'. Cảm ơn! –

+3

Thay thế '5 + 1' bằng 'None' nó cũng hoạt động và đọc đơn giản hơn –

-1

Có lẽ bạn nên giải thích thêm về trường hợp sử dụng thực tế.

>>> gen = xrange(10) 
>>> ind=5 
>>> gen[ind] 
5 
+4

Tôi đã chỉnh sửa 'xrange (10)' thành '(i cho i trong xrange (10))'. Hóa ra cú pháp này hoạt động cho 'xrange' vì nó không thực sự là máy phát ... –

+5

' xrange' đặt trước máy phát, và trả về một đối tượng xrange, thực sự thực hiện giao thức chuỗi đầy đủ. –

14

Bạn có thể làm điều này, sử dụng count làm ví dụ máy phát điện:

from itertools import islice, count 
next(islice(count(), n, n+1)) 
+0

Phiên bản Python nào? Đoạn mã trên cho tôi lỗi "AttributeError: 'itertools.islice' đối tượng không có thuộc tính 'next'' trong 3.3. – LarsH

+0

Trong Python 3x, thay đổi 'next' thành' __next __() ', tức là' islice (count, n, n = 1) .__ next __() ' – Mohammed

+2

Vì vậy, tốt hơn nên sử dụng' next (islice (count(), n , n + 1)) '. –

-2

bạn chỉ có thể chuyển đổi các máy phát điện vào một danh sách và sử dụng chỉ mục như bình thường:

>>> [i for i in range(10)][index] 
5 
3

Tôi muốn chống lại sự cám dỗ để xử lý các máy phát điện như danh sách. Cách tiếp cận đơn giản nhưng ngây thơ là một lớp lót đơn giản:

gen = (i for i in range(10)) 
list(gen)[3] 

Nhưng hãy nhớ rằng, máy phát không giống như danh sách. Họ không lưu trữ kết quả trung gian của họ ở bất cứ nơi nào, vì vậy bạn không thể đi ngược lại. Tôi sẽ chứng minh vấn đề với một ví dụ đơn giản trong repl python:

>>> gen = (i for i in range(10)) 
>>> list(gen)[3] 
3 
>>> list(gen)[3] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
IndexError: list index out of range 

Khi bạn bắt đầu trải qua một máy phát điện để có được giá trị thứ n trong dãy, máy phát điện tại là ở tiểu bang khác, và cố gắng nhận lại giá trị thứ n sẽ trả lại cho bạn một kết quả khác, điều này có khả năng dẫn đến lỗi trong mã của bạn.

Hãy xem một ví dụ khác, dựa trên mã từ câu hỏi.

Ban đầu, người ta sẽ mong đợi những điều sau đây để in 4 hai lần.

gen = (i for i in range(10)) 
index = 4 
for i, v in enumerate(gen): 
    if i == index: 
     answer = v 
     break 
print(answer) 
for i, v in enumerate(gen): 
    if i == index: 
     answer = v 
     break 
print(answer) 

nhưng gõ này vào repl và bạn nhận được:

>>> gen = (i for i in range(10)) 
>>> index = 4 
>>> for i, v in enumerate(gen): 
...  if i == index: 
...    answer = v 
...    break 
... 
>>> print(answer) 
4 
>>> for i, v in enumerate(gen): 
...  if i == index: 
...    answer = v 
...    break 
... 
>>> print(answer) 
9 

Chúc may mắn truy tìm lỗi xuống.

0

Điều đầu tiên mà đến tâm trí của tôi là:

gen = (i for i in xrange(10)) 
index = 5 

for i, v in zip(range(index), gen): pass 

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