实现一个range

作者:酱油哥
链接:https://www.zhihu.com/question/20829330/answer/286837159
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

class MyRange(collections.Iterator):
    def __init__(self, bound):
        self.cur = -1
        self.bound = bound
    def __iter__(self):
        return self
    def __next__(self):
        if self.cur < self.bound:
            self.cur += 1
            return self.cur
        else:
            raise StopIteration

就需要写这些,就和java一样,非常麻烦。但是有了generator,

def my_range(bound):
    for i in range(stop):
        yield i

可迭代对象分为两大类,一种是实际保存的序列,即列表、元组,字符串;另一种就是我们上一节总提到的“不一次性产生所有结果列表,而是可以在for循环中按需一次产生一个结果的对象”。 如:range函数返回值、zip函数返回值、enumerate函数返回值等等,与实际序列相对应,这个叫做按需产生对象的虚拟序列。
可迭代对象支持内置函数iter,通过对可迭代对象调用iter函数,会返回一个迭代器,而“迭代器”支持内置函数next,通过不断对其调用next方法,会依次前进到序列中的下一个元素并将其返回,最后到达一系列结果的末尾时,会引发StopIteration异常。补充说明一点,对迭代器调用iter方法,则会返回迭代器自身。

L = [2,3,4]
I = iter(L)
print(iter(L))
print(I is L)
print(I is iter(I))

<list_iterator object at 0x00000000021E0978>
False
True

我们来完整的看看迭代过程是怎么实现的:当任何可迭代对象传入到for循环或其他迭代工具中进行遍历时,迭代工具都是先通过iter函数获得与可迭代对象对应的迭代器,然后再对迭代器调用next函数,不断的依次获取元素,并在捕捉到StopIteration异常时确定完成迭代,这就是完整的迭代过程。这也称之为“迭代协议”。
文件对象
open函数返回的已打开的文件对象,也是可以一行一行的读取,直至文件结束,那很显然,他也是可迭代对象。

f = open('myfile.txt')
print(f is iter(f))

True

原始的readlines方法

f = open('myfile.txt')
for line in f.readlines():
print(line, end='')

hello text file
goodbyt text file
Hahahahah

对应的,直接用for循环来进行自动迭代

f = open('myfile.txt')
for line in f:
print(line, end='')

hello text file
goodbyt text file
Hahahahah

对比来看,虽然readlines方法在功能上可用,但从内存上来看,非常糟糕,他是一次性把整个文件加载到内存,如果文件太大,以至于计算机内存不够,甚至不能够工作。而我们的迭代器版本则不然,迭代器是按需,一次只读取一行,因此对内存爆炸问题有了很好的免疫。
字典类型
文件和列表对象都是实际的序列,他所迭代的就是他的实际内容,那字典呢?字典也是一种可迭代对象,但是他的迭代器却比较特殊。我们看看手动模拟迭代过程的例子:

D = {'a':1, 'b':2, 'c':3}
I = iter(D)
print(next(I))
print(next(I))
print(next(I))
print(next(I))

a
b
c
Traceback (most recent call last):
 File "E:/12homework/12homework.py", line 6, in <module>
print(next(I))
StopIteration

同样,在for循环中自动迭代的例子如下:

D = {'a':1, 'b':2, 'c':3}
for k in D:
print(k)

c
a
b

因此不难看出,字典也是一个可迭代对象,字典有一个迭代器,在迭代环境中,会每次自动地返回一个键。而需要补充的是,字典拥有不同视图的可迭代对象,这里就不详细一一展开了,看看几个例子,分别是各自不同视图下的可迭代对象和迭代器,他们也是一次产生一个结果项,而不是在内存中一次产生全部结果列表。

D = {'a':1,'b':2,'c':3}
print(D.keys())
print(iter(D.keys()))
print(D.values())
print(iter(D.values()))
print(D.items())
print(iter(D.items()))

dict_keys(['b', 'a', 'c'])
<dict_keyiterator object at 0x0000000002202958>
dict_values([2, 1, 3])
<dict_valueiterator object at 0x0000000002202958>
dict_items([('b', 2), ('a', 1), ('c', 3)])
<dict_itemiterator object at 0x00000000022029A8>

再举两个我们上一节提到的例子:range函数和enumerate函数
range函数的返回值是一个可迭代对象,同理利用iter方法也可以得到他的迭代器

R = range(5)
I = iter(R)
print(R)
print(I)

range(0, 5)
<range_iterator object at 0x0000000002191A30>

enumerate方法返回的也是可迭代对象,他的迭代器就是他自身

E = enumerate('spam')
print(E)
print(iter(E))

<enumerate object at 0x00000000021F2558>
<enumerate object at 0x00000000021F2558>

可迭代对象按照需求,一次只返回一个结果,而不是一口气一次性的返回一个对象列表,因此我们必须把可迭代对象包裹在一个list调用中,从而才能一次性看到它们所有的值。

print(list(enumerate('spam')))
[(0, 's'), (1, 'p'), (2, 'a'), (3, 'm')] 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值