Danh sách Python hành vi lặp và tiếp theo (iterator)


147

Xem xét:

>>> lst = iter([1,2,3])
>>> next(lst)
1
>>> next(lst)
2

Vì vậy, tiến bộ iterator, như mong đợi, được xử lý bằng cách biến đổi cùng một đối tượng.

Đây là trường hợp, tôi mong đợi:

a = iter(list(range(10)))
for i in a:
   print(i)
   next(a)

để bỏ qua mọi phần tử thứ hai: lệnh gọi nextsẽ tiến lên trình lặp một lần, sau đó cuộc gọi ngầm được thực hiện bởi vòng lặp sẽ chuyển tiếp lần thứ hai - và kết quả của cuộc gọi thứ hai này sẽ được gán cho i.

Nó không. Vòng lặp in tất cả các mục trong danh sách, mà không bỏ qua bất kỳ mục nào.

Suy nghĩ đầu tiên của tôi là điều này có thể xảy ra bởi vì vòng lặp gọi iternhững gì nó được thông qua và điều này có thể mang lại một trình vòng lặp độc lập - đây không phải là trường hợp như chúng ta có iter(a) is a.

Vì vậy, tại sao nextkhông xuất hiện để thúc đẩy iterator trong trường hợp này?

Câu trả lời:


197

Những gì bạn thấy là trình thông dịch lặp lại giá trị trả về next()ngoài việc iđược in mỗi lần lặp:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    next(a)
... 
0
1
2
3
4
5
6
7
8
9

Vì vậy, 0đầu ra của print(i), 1giá trị trả về từ next(), được lặp lại bởi trình thông dịch tương tác, v.v ... Chỉ có 5 lần lặp, mỗi lần lặp lại dẫn đến 2 dòng được ghi vào thiết bị đầu cuối.

Nếu bạn chỉ định đầu ra của next()những thứ hoạt động như mong đợi:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    _ = next(a)
... 
0
2
4
6
8

hoặc in thêm thông tin để phân biệt print()đầu ra với tiếng vang của trình thông dịch tương tác:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print('Printing: {}'.format(i))
...    next(a)
... 
Printing: 0
1
Printing: 2
3
Printing: 4
5
Printing: 6
7
Printing: 8
9

Nói cách khác, next()đang hoạt động như mong đợi, nhưng vì nó trả về giá trị tiếp theo từ trình vòng lặp, được lặp lại bởi trình thông dịch tương tác, nên bạn được tin rằng vòng lặp có bản sao lặp riêng của nó bằng cách nào đó.


13
Tôi đã không nhận thức được hành vi này từ người phiên dịch. Tôi vui vì tôi đã phát hiện ra rằng trước khi mất rất nhiều thời gian tự hỏi về nó trong khi giải quyết một số vấn đề thực sự.
brandizzi

5
... * chết *. Điều tồi tệ nhất của nó là, tôi có thể nhớ rằng đã đề cập chính xác hành vi phiên dịch viên này cho ai đó có lẽ một tuần trước.
lvc

hấp dẫn. Tôi đã thử cho tôi trong một: next (a); in i và nghĩ rằng tôi sẽ nhảy lên 1 và in 1,3,5,7,9. Nhưng nó vẫn là 0,2,4,6,8. Tại sao?
dùng2290820

3
iđã được chỉ định. next(a)có nghĩa là lần lặp tiếp theo 2được gán cho i, sau đó bạn di chuyển alại, in i, v.v.
Martijn Pieters

1
Điều này không hoạt động nếu n là số lẻ - StopIterationexcepetio nis được nêu ra khi next(a)được gọi sau khi danh sách hết.
Raf

13

Điều đang xảy ra là next(a)trả về giá trị tiếp theo của a, được in ra bàn điều khiển vì nó không bị ảnh hưởng.

Những gì bạn có thể làm là ảnh hưởng đến một biến có giá trị này:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    b=next(a)
...
0
2
4
6
8

8

Tôi thấy các câu trả lời hiện có một chút khó hiểu, bởi vì chúng chỉ gián tiếp chỉ ra điều bí ẩn cần thiết trong ví dụ mã: cả * "in i" và "tiếp theo (a)" đều khiến kết quả của chúng được in.

Vì họ đang in các phần tử xen kẽ của chuỗi gốc và không ngờ rằng câu lệnh "next (a)" đang in, nó xuất hiện như thể câu lệnh "print i" đang in tất cả các giá trị.

Trong ánh sáng đó, rõ ràng hơn là việc gán kết quả của "next (a)" cho một biến sẽ ngăn cản việc in kết quả của nó, do đó chỉ các giá trị thay thế mà biến vòng lặp "i" được in. Tương tự như vậy, làm cho câu lệnh "in" cũng phát ra thứ gì đó đặc biệt hơn làm rõ ràng nó.

(Một trong những câu trả lời hiện có bác bỏ những câu trả lời khác vì câu trả lời đó có mã ví dụ được đánh giá là một khối, do đó trình thông dịch không báo cáo các giá trị trung gian cho "next (a)".)

Nói chung, điều khó hiểu trong việc trả lời các câu hỏi, nói chung, là rõ ràng về những gì là hiển nhiên một khi bạn biết câu trả lời. Nó có thể khó nắm bắt. Tương tự như vậy, các câu trả lời phê bình một khi bạn hiểu chúng. Thật thú vị...


2

Có gì đó không ổn với Python / Computer của bạn.

a = iter(list(range(10)))
for i in a:
   print(i)
   next(a)

>>> 
0
2
4
6
8

Hoạt động như mong đợi.

Đã thử nghiệm trong Python 2.7 và trong Python 3+. Hoạt động đúng trong cả hai


5
Tôi nhận được kết quả tương tự như @lvc (chỉ trên IDLE, tuy nhiên, khi được thực thi như tập lệnh tôi nhận được điều này))
jamylak

3
@Inbar Rose Chỉ khi bạn chạy dưới dạng tập lệnh.
Quintec

1
đó là hành vi đặt mã thông qua shell tương tác. Nếu hàm trả về giá trị mà không được sử dụng, trình thông dịch sẽ in nó sang shell dưới dạng đầu ra gỡ lỗi
Reishin

2

Đối với những người vẫn chưa hiểu.

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    next(a)
... 
0 # print(i) printed this
1 # next(a) printed this
2 # print(i) printed this
3 # next(a) printed this
4 # print(i) printed this
5 # next(a) printed this
6 # print(i) printed this
7 # next(a) printed this
8 # print(i) printed this
9 # next(a) printed this

Như những người khác đã nói, nexttăng iterator lên 1 như mong đợi. Việc gán giá trị trả về của nó cho một biến không làm thay đổi hành vi của nó một cách kỳ diệu.


1

Nó hoạt động theo cách bạn muốn nếu được gọi là một hàm:

>>> def test():
...     a = iter(list(range(10)))
...     for i in a:
...         print(i)
...         next(a)
... 
>>> test()
0
2
4
6
8
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.