Nếu range () là một trình tạo trong Python 3.3, tại sao tôi không thể gọi next () trên một dải?


84

Có lẽ tôi đã trở thành nạn nhân của thông tin sai lệch trên web, nhưng tôi nghĩ nhiều khả năng tôi đã hiểu sai điều gì đó. Dựa trên những gì tôi đã học cho đến nay, range () là một trình tạo và các trình tạo có thể được sử dụng như các trình vòng lặp. Tuy nhiên, mã này:

myrange = range(10)
print(next(myrange))

cho tôi lỗi này:

TypeError: 'range' object is not an iterator

Tôi còn thiếu gì ở đây? Tôi đã mong đợi điều này sẽ in 0 và chuyển sang giá trị tiếp theo trong myrange. Tôi là người mới sử dụng Python, vì vậy xin chấp nhận lời xin lỗi của tôi về câu hỏi khá cơ bản, nhưng tôi không thể tìm thấy lời giải thích tốt ở bất kỳ nơi nào khác.


2
Xem stackoverflow.com/q/13054057/395760 để biết sự phân biệt giữa các trình vòng lặp và những thứ mà bạn có thể lặp lại trong một forvòng lặp.

1
Có chính xác không khi nói rằng trình tạo là các tệp lặp, nhưng không phải là trình lặp?
Jeff

4
@Jeff Iterables là các đối tượng itercó thể được sử dụng để lấy một trình lặp. Trình lặp là các đối tượng có thể được lặp lại thông qua việc sử dụng next. Máy phát điện là một danh mục của trình lặp (hàm máy phát và biểu thức máy phát). Ít nhất đó là những gì tôi nghĩ ...
Oleh Prypin

Câu trả lời:


109

rangelà một lớp các đối tượng có thể lặp lại bất biến. Hành vi lặp lại của chúng có thể được so sánh với lists: bạn không thể gọi nexttrực tiếp trên chúng; bạn phải có được một trình lặp bằng cách sử dụng iter.

Vì vậy, không, rangekhông phải là một máy phát điện.

Bạn có thể đang nghĩ, "tại sao họ không làm cho nó có thể lặp lại trực tiếp"? Chà, ranges có một số thuộc tính hữu ích mà không thể theo cách đó:

  • Chúng là bất biến, vì vậy chúng có thể được sử dụng làm khóa từ điển.
  • Họ có start, stopstepcác thuộc tính (kể từ Python 3.3), countindexcác phương pháp và họ hỗ trợ in, len__getitem__các hoạt động.
  • Bạn có thể lặp lại rangenhiều lần giống nhau .

>>> myrange = range(1, 21, 2)
>>> myrange.start
1
>>> myrange.step
2
>>> myrange.index(17)
8
>>> myrange.index(18)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 18 is not in range
>>> it = iter(myrange)
>>> it
<range_iterator object at 0x7f504a9be960>
>>> next(it)
1
>>> next(it)
3
>>> next(it)
5

11
Một tính năng tốt đẹp của rangeđối tượng là họ có một __contains__phương pháp có thể được sử dụng để kiểm tra xem một giá trị trong một phạm vi:5 in range(10) => True
kindall

Cảm ơn vì câu trả lời; điều này có ý nghĩa ngay bây giờ. Điều duy nhất tôi muốn làm sáng tỏ trước khi chấp nhận câu trả lời của bạn là lưu ý in nghiêng khoảng một phần ba các con đường xuống này trang, rằng các quốc gia rằng "bằng Python 3 dãy () là một máy phát điện". Điều này có đơn giản là không chính xác?
Jeff

3
@Jeff Nói đúng ra là có, sai rồi. Tác giả của ghi chú có lẽ có nghĩa là trong Python 3 rangelười biếng (so với Python 2, nơi nó chỉ là một hàm trả về một danh sách).
Oleh Prypin

6
Ngoài ra: range(0,10,3)[3]9 in range(0,10,3). Phạm vi là một danh sách khá nhiều lười biếng.
Lennart Regebro 27/10/12

2
@ user3079275 "có thể lặp lại trực tiếp" là một từ viết sai, thực sự có nghĩa là "trình lặp". Các trình lặp có trạng thái bên trong và do đó có thể thay đổi theo định nghĩa. "Lặp lại" là một đối tượng, cho dù nó có thể thay đổi được hay không, có thể tạo ra một trình lặp. Ngay cả các đối tượng có thể thay đổi thường không phải là bản thân các trình vòng lặp, thay vào đó chúng tạo ra các trình vòng lặp theo cách có thể sử dụng lại (ví dụ: bạn có thể lặp lại cùng một danh sách ở hai nơi khác nhau một cách độc lập, sử dụng hai trình vòng lặp).
Oleh Prypin
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.