2012-10-26 10 views
42

Có lẽ tôi đã trở thành nạn nhân của thông tin sai lạc trên web, nhưng tôi nghĩ rằng nó có nhiều khả năng chỉ là tôi đã hiểu lầm một cái gì đó. Dựa trên những gì tôi đã học đượ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 lặp. Tuy nhiên, mã này: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ãy?

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

mang lại cho tôi lỗi này:

TypeError: 'range' object is not an iterator 

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

+1

Xem http://stackoverflow.com/q/13054057/395760 cho sự phân biệt giữa lặp và những thứ mà bạn có thể duyệt qua trong một 'vòng for'. – delnan

+0

Sẽ đúng khi nói rằng máy phát điện có thể lặp lại, nhưng không phải là máy lặp? – Jeff

+1

@Jeff Iterables là các đối tượng mà 'iter' có thể được sử dụng để có được một trình lặp. Các Iterator 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ác trình lặp (các hàm máy phát và các biểu thức máy phát). Ít nhất đó là những gì tôi nghĩ ... –

Trả lời

50

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

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

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

  • Chúng không thay đổi, vì vậy chúng có thể được sử dụng làm khóa từ điển.
  • Họ có start, stopstep thuộc tính (kể từ Python 3.3), countindex phương pháp và họ hỗ trợ in, len__getitem__ hoạt động.
  • Bạn có thể lặp lại trên cùng một range nhiều lần.

>>> 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 
+4

Một tính năng thú vị khác của đối tượng 'range' là chúng có phương thức' __contains__' có thể được sử dụng để kiểm tra xem một giá trị có nằm trong phạm vi không: '5 trong phạm vi (10) => True' – kindall

+0

Cảm ơn câu trả lời; điều này có ý nghĩa 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à ghi chú in nghiêng về một phần ba của trang xuống [this] (http://wiki.python.org/moin/Generators), mà nói rằng "bằng Python 3 phạm vi() là một máy phát điện ". Điều này chỉ đơn giản là không chính xác? – Jeff

+2

@Jeff Nói đúng, có, nó sai. Tác giả của ghi chú có thể có nghĩa là trong Python 3 'range' là * lazy * (so với Python 2, nó chỉ là một hàm trả về một danh sách). –