为什么要写这个文档,感觉自己学了这么久python,感觉白学了,一直都用C++的思想去看python代码,基础完全没学好,感觉很混乱。
for(int i=0;i<100;i++)
cout<<i<<endl;
for i in range(0,100)
print(i)
在C++,for循环是首先执行i=0,然后在比较i<100、循环中的语句、i++ 之间重复,直到不满足判断。
而python的for循环,range返回的是一个迭代器。我们可以将循环理解成下列步骤。首先,range生成一个列表,range 通过__iter__函数将这些数据转变为一个迭代器,每次for循环会执行一次__next__函数调用里面的数据,而访问到数组最后没有数据的时候,会弹出一个StopIteration,迭代结束。
再加一点,其实确切的说,不只是range,,而更应该是for in 这中语句就会抽取出对应的迭代器,像下列代码,没有range,也能实现for循环,可能是python的一个语法包容性吧,具体python编译这些代码的底层我还没有学到,可能以后会写一篇文档吧。
# 迭代列表
L = [1,2,3,4,5]
for element in L:
print(str(element) * 3)
# 迭代字符串
S = 'PYTHON'
for s in S:
print(s * 3)
# 迭代元组
L = (1,2,3,4,5)
for element in L:
print(str(element) * 3)
# 迭代集合
G = {'Ruo', 'Data', 'Python'}
for g in G:
print(g)
# 迭代文件
for line in open('ex.txt'):
print(line, end='')
这就是python和C++for循环的区别。
讲完迭代器,引申一个python生成器的概念。
def fib(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
yield a
def main():
for val in fib(20):
print(val)
if __name__ == '__main__':
main()
这里面的函数返回并不是使用一个return,而是使用一个yield,这两者有什么区别呢,如果我们使用return来完成上述的代码,就应该是这样
def fib(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return a
def main():
for val in range(20):
print(fib(val))
我猜很多人可能是写这种代码的,但是我们会发现,下面这份代码总共运行a, b = b, a + b 共210次,而上面有yield的代码只执行了20次。
ps: 有人肯定会说,你直接把for循环写在main函数里不就行了,或者是把print写在fib里面。但是本文讨论的是在函数中return和yield的区别,就不要吹毛求疵了。
然后我们来讲讲yield,讲yield就离不开生成器,包含yield的函数本质上不可以把它看成一个函数,它是一个生成器。而生成器是一种特殊的迭代器,这就为什么我一开始需要讲迭代器的原因。
上一小结里的迭代器,每次会按照__next__方法依次生成下一个数据,因此当前状态需要保存,而实现这些操作我们可以用一种更强大的语法来实现,就是生成器。
L = [ x*2 for x in range(5)] # 列表推导式
print(L) # [0, 2, 4, 6, 8]
G = ( x*2 for x in range(5)) # 生成器
print(G)
# at 0x7f43c0818780>
# 调用生成器 这是python3 和python2的next()不一样
print(G.__next__()) # 输出 0
print(G.__next__()) # 输出 2
当然,我们一般也不会建个生成器去不停__next__() 我们一般就将它用在for循环,或者就是函数迭代上,现在回到那个fibnaci函数里去。
含有yield的函数,即生成器,它本身会包含一个功能,记录当前运行的状态,再次访问生成器时会从原先的状态继续运行,直到生成器停止迭代。在上面代码就是每次for循环暂停一次,下次进入生成器在继续循环,直到循环结束
ps:python3 生成器可以加return,当生成器遇到return时,当前的生成器就被结束了。
def fib(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
yield a
return a
def main():
for val in fib(20):
print(val)
if __name__ == '__main__':
main()
# 最终只会输出 1