ars*_*ars 622
python中的迭代器对象符合迭代器协议,这基本上意味着它们提供了两种方法:__iter__()
和 __next__()
.在__iter__
返回迭代器对象,并隐式调用在循环的开始.该__next__()
方法返回下一个值,并在每个循环增量处隐式调用. __iter__()
当没有更多值返回时引发StopIteration异常,循环结构隐式捕获该异常以停止迭代.
这是一个简单的计数器示例:
class Counter:
def __init__(self, low, high):
self.current = low - 1
self.high = high
def __iter__(self):
return self
def __next__(self): # Python 2: def next(self)
self.current += 1
if self.current < self.high:
return self.current
raise StopIteration
for c in Counter(3, 9):
print(c)
Run Code Online (Sandbox Code Playgroud)
这将打印:
3
4
5
6
7
8
Run Code Online (Sandbox Code Playgroud)
使用生成器更容易编写,如前面的答案所述:
def counter(low, high):
current = low
while current < high:
yield current
current += 1
for c in counter(3, 9):
print(c)
Run Code Online (Sandbox Code Playgroud)
打印输出将是相同的.在引擎盖下,生成器对象支持迭代器协议,并执行与类Counter类似的操作.
David Mertz的文章,Iterators和Simple Generators,是一个非常好的介绍.
Eth*_*man 396
有四种方法可以构建迭代函数:
__iter__
和__next__
(或next
在Python 2.x中))__getitem__
)例子:
# generator
def uc_gen(text):
for char in text:
yield char.upper()
# generator expression
def uc_genexp(text):
return (char.upper() for char in text)
# iterator protocol
class uc_iter():
def __init__(self, text):
self.text = text
self.index = 0
def __iter__(self):
return self
def __next__(self):
try:
result = self.text[self.index].upper()
except IndexError:
raise StopIteration
self.index += 1
return result
# getitem method
class uc_getitem():
def __init__(self, text):
self.text = text
def __getitem__(self, index):
result = self.text[index].upper()
return result
Run Code Online (Sandbox Code Playgroud)
要查看所有四种方法:
for iterator in uc_gen, uc_genexp, uc_iter, uc_getitem:
for ch in iterator('abcde'):
print ch,
print
Run Code Online (Sandbox Code Playgroud)
结果如下:
A B C D E
A B C D E
A B C D E
A B C D E
Run Code Online (Sandbox Code Playgroud)
注意:
两种发电机类型(uc_gen
和uc_genexp
)不能reversed()
; plain iterator(uc_iter
)需要__reversed__
magic方法(必须返回一个向后的新迭代器); 并且getitem iteratable(uc_getitem
)必须具有__len__
魔术方法:
# for uc_iter
def __reversed__(self):
return reversed(self.text)
# for uc_getitem
def __len__(self)
return len(self.text)
Run Code Online (Sandbox Code Playgroud)
要回答Panic上校关于无限延迟评估迭代器的第二个问题,下面是这些例子,使用上述四种方法中的每一种:
# generator
def even_gen():
result = 0
while True:
yield result
result += 2
# generator expression
def even_genexp():
return (num for num in even_gen()) # or even_iter or even_getitem
# not much value under these circumstances
# iterator protocol
class even_iter():
def __init__(self):
self.value = 0
def __iter__(self):
return self
def __next__(self):
next_value = self.value
self.value += 2
return next_value
# getitem method
class even_getitem():
def __getitem__(self, index):
return index * 2
import random
for iterator in even_gen, even_genexp, even_iter, even_getitem:
limit = random.randint(15, 30)
count = 0
for even in iterator():
print even,
count += 1
if count >= limit:
break
print
Run Code Online (Sandbox Code Playgroud)
这导致(至少我的样本运行):
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32
Run Code Online (Sandbox Code Playgroud)
akd*_*dom 102
首先,itertools模块对于迭代器很有用的各种情况非常有用,但是这里只需要在python中创建一个迭代器:
让
那不是很酷吗?Yield可用于替换函数中的正常返回.它返回的对象是相同的,但它不是破坏状态和退出,而是为你想要执行下一次迭代时保存状态.以下是直接从itertools函数列表中提取的操作示例:
def count(n=0):
while True:
yield n
n += 1
Run Code Online (Sandbox Code Playgroud)
正如函数描述中所述(它是来自itertools模块的count()函数...),它产生一个迭代器,它返回以n开头的连续整数.
生成器表达式是另一种蠕虫(真棒蠕虫!).可以使用它们代替List Comprehension来节省内存(列表推导在内存中创建一个列表,如果没有分配给变量,在使用后会被销毁,但生成器表达式可以创建一个生成器对象...这是一种奇特的方式说Iterator).以下是生成器表达式定义的示例:
gen = (n for n in xrange(0,11))
Run Code Online (Sandbox Code Playgroud)
这与上面的迭代器定义非常相似,只是整个范围预定在0到10之间.
我刚刚找到xrange()(我以前没见过它而感到惊讶......)并将它添加到上面的例子中. xrange()是range()的可迭代版本,其优点是不预先构建列表.如果你有一个巨大的数据集来迭代并且只有这么多的内存来完成它将是非常有用的.
Man*_*nux 99
我看到一些你做return self
在__iter__
.我只是想指出,__iter__
本身可以是一台发电机(从而消除了需要__next__
和提高StopIteration
例外)
class range:
def __init__(self,a,b):
self.a = a
self.b = b
def __iter__(self):
i = self.a
while i < self.b:
yield i
i+=1
Run Code Online (Sandbox Code Playgroud)
当然,这里也可以直接生成一个生成器,但对于更复杂的类,它可能很有用.
小智 12
这个问题是关于可迭代的对象,而不是迭代器.在Python中,序列也是可迭代的,因此制作可迭代类的一种方法是使其行为像序列,即给它__getitem__
和__len__
方法.我在Python 2和3上测试了这个.
class CustomRange:
def __init__(self, low, high):
self.low = low
self.high = high
def __getitem__(self, item):
if item >= len(self):
raise IndexError("CustomRange index out of range")
return self.low + item
def __len__(self):
return self.high - self.low
cr = CustomRange(0, 10)
for i in cr:
print(i)
Run Code Online (Sandbox Code Playgroud)
如果您正在寻找简短而简单的东西,也许对您来说就足够了:
class A(object):
def __init__(self, l):
self.data = l
def __iter__(self):
return iter(self.data)
Run Code Online (Sandbox Code Playgroud)
用法示例:
In [3]: a = A([2,3,4])
In [4]: [i for i in a]
Out[4]: [2, 3, 4]
Run Code Online (Sandbox Code Playgroud)
小智 6
在您的类代码中包含以下代码。
def __iter__(self):
for x in self.iterable:
yield x
Run Code Online (Sandbox Code Playgroud)
确保更换self.iterable
为您迭代的可迭代对象。
这是一个示例代码
class someClass:
def __init__(self,list):
self.list = list
def __iter__(self):
for x in self.list:
yield x
var = someClass([1,2,3,4,5])
for num in var:
print(num)
Run Code Online (Sandbox Code Playgroud)
输出
1
2
3
4
5
Run Code Online (Sandbox Code Playgroud)
注意:由于字符串也是可迭代的,因此它们也可以用作类的参数
foo = someClass("Python")
for x in foo:
print(x)
Run Code Online (Sandbox Code Playgroud)
输出
P
y
t
h
o
n
Run Code Online (Sandbox Code Playgroud)
对于复杂的对象,此页面上的所有答案都非常有用。但对于含有内置的迭代类型,属性那些像str
,list
,set
或dict
,或任何实现collections.Iterable
,你可以在你的类省略某些事情。
class Test(object):
def __init__(self, string):
self.string = string
def __iter__(self):
# since your string is already iterable
return (ch for ch in self.string)
# or simply
return self.string.__iter__()
# also
return iter(self.string)
Run Code Online (Sandbox Code Playgroud)
可以像这样使用:
for x in Test("abcde"):
print(x)
# prints
# a
# b
# c
# d
# e
Run Code Online (Sandbox Code Playgroud)