python 里的可迭代对象都有以下方法
def __iter__(self, *args, **kwargs): # real signature unknown
""" Implement iter(self). """
pass
实现了iter(self) 函数
接下来查看iter() 函数
def iter(source, sentinel=None): # known special case of iter
"""
iter(iterable) -> iterator
iter(callable, sentinel) -> iterator
Get an iterator from an object. In the first form, the argument must
supply its own iterator, or be a sequence.
In the second form, the callable is called until it returns the sentinel.
"""
pass
iter() 函数可以有一个或两个参数
有一个参数时,iter(iterable) -> iterator ,Get an iterator from an object(获取对象的迭代器),In the first form, the argument must
supply its own iterator, or be a sequence.(在第一种形式中,即只有一个参数的时候,该对象自身需要提供迭代器,也就是有自己的iter函数,或者该对象是一个队列)
python 的基本数据类型中,有iter函数的有字符串(str),列表(list),元组(tuple),集合(set),字典(dict)
接下来去看看官方文档对iter()函数的解释
python各种版本的文档
3.6.4版本的iter()函数直通车
iter(object[, sentinel])方法在给定第二个参数的时候,则object必须是可调用的对象,iter()方法创建了一个迭代器,每次调用这个迭代器的__next()__方法的时候,都会调用object参数,如果next()方法返回值等于sentinel,将会引发StopIteration,不等于则返回方法返回值.
这里需要注意,python里有个函数callable(object) 可以判断一个对象是否是可调用的,如果对象显示可调用,则返回True,否则返回False,返回True的话,调用有可能失败,如果返回False的话,永远不可能被调用.类是可以被调用的,调用一个类返回一个新实例对象,如果实例对象所属的类有个__call()__方法的话,该实例对象也是可以被调用的.
callable() 这个函数在Python 3.0被删除,后来在3.2版本里又回归了.
#例子一
class A:
def __init__(self):
self.list1 = [1, 2, 3, 4, 5, 6, 7]
print('init()被调用')
def __call__(self):
print('call()被调用')
return next(self)
def __iter__(self):
print('iter()被调用')
self.i = 0
return self.list1
def __next__(self):
if self.i < len(self.list1):
print('next()方法调用')
next_value = self.list1[self.i]
self.i += 1
return next_value
else:
raise StopIteration
if __name__ == '__main__':
print(callable(A())) # init()被调用 True
a = A()
print(callable(a)) # init()被调用 True
i = iter(a, 5)
print(type(i)) # <class 'callable_iterator'>
for x in i:
print(x)
'''
call()被调用
next()方法调用
1
call()被调用
next()方法调用
2
call()被调用
next()方法调用
3
call()被调用
next()方法调用
4
call()被调用
next()方法调用
'''
#例子二
i = 0
def getNum():
global i
i += 1
return i
print(callable(getNum))
a = iter(getNum, 5)
for x in a:
print(x)
'''
True
1
2
3
4
'''
yield
yield表达式在定义生成器函数或异步生成器函数时使用,因此只能在函数定义的主体中使用,在函数体中使用yield会使该函数称为生成器函数.
调用生成器函数时,将返回一个名为生成器的迭代器,该生成器控制着生成器函数的执行,当调用生成器的方法的时候,开始执行生成器函数.执行到第一个yield表达式的时候,该生成器函数被挂起,然后将expression_list格式的值返回给生成器的调用方,
expression_list ::= expression ( “,” expression )* [","]
这里挂起的意思是,保留所有的局部状态,包括局部变量的当前绑定值,指令指针,内部堆栈和任何异常处理的状态.当调用生成器的方法时,恢复执行状态,类似于生成器函数被重新调用一样,只不过是从上次挂起的地方开始.之后的yield表达式的值取决于恢复执行状态时被调用的生成器的方法.
如下例子debug分析具体过程:
# -*- coding:utf-8 -*-
def getNum(n):
a = 1
while True:
if a > n:
return
yield a
print(a, a * 2, a * 3)
a += 1
if __name__ == '__main__':
num = getNum(3)
print(type(num))
while True:
try:
next(num)
except:
exit()
- 在num=getNum(3) 和 next(num) 处打断点,debug运行程序
- getNum()返回一个num,类型为generator
- 当程序运行到next()的时候,getNum()开始执行,执行到yield的时候不往下继续,此时a=1,next()执行完
- 然后开始第二次执行next(),跳到getNum()函数,继续执行yield之后的代码,print(a, a * 2, a * 3),[结果是 1,2,3]然后a变成2,继续循环,判断if代码,第二次执行到yield,然后不往下继续,next()执行完
- 然后继续执行next()所在的循环,第三次执行next(),然后跳转到getNum()函数,执行print(a, a * 2, a * 3),[结果是2 4 6],a自增1变成3,继续执行getNum()函数的循环,if判断,yield a,不往下继续执行,跳到next()执行完
- 执行next()所在循环,第四次执行next(),跳转到getNum(),继续执行,print(a, a * 2, a * 3),[结果是 3 6 9],a自增1变成4,if判断通过getNum()函数return,跳到next(),程序捕获异常,退出
后续的协程,yield from 在之后多线程的地方研究.