python函数
一、迭代器
1、可迭代对象
for i in 100: print(i) # TypeError: 'int' object is not iterable
2、判断一个对象是否是iterable对象
from collections.abc import Iterable a = [1, 3, 4] # 判断一个对象是否是可迭代对象 print(isinstance(a, Iterable))
3、可迭代对象的本质
s = 'hello world' # s可迭代对象 i = s.__iter__() # i迭代器 print(i.__next__()) # 取出第一个值 print(i.__next__()) # 取出第二个值 print(i.__next__()) # 取出第三个值 ...
同样也可以通过iter()函数获取一个迭代器对象,然后使用next()函数来获取对象中的每一个数据。
s = 'hello world' # s可迭代对象 i = iter(s) # i迭代器 print(next(i)) # 取出第一个值 print(next(i)) # 取出第二个值 print(next(i)) # 取出第三个值 ...
注意:当使用__next__()或next()取完最后一个值后,再调用__next__()或next()会报异常:StopIteration(停止迭代)
4、普通类的可迭代
普通的类不是可迭代对象,但类定义中重写了__iter__()魔法方法,类就变成了可迭代对象。
from collections.abc import Iterable class Demo: def __init__(self, x): pass def __iter__(self): # 重写方法 pass d = Demo(1) print(isinstance(d, Iterable)) # True
5、for...in的本质
for...in的本质就是调用可迭代对象的__iter__方法,获得这个方法的返回值,这个返回值需要时一个对象,然后在调用这个对象的__next__方法。
class Foo: def __next__(self): return [1, 2, 3] class Demo: def __init__(self): pass def __iter__(self): return Foo() d = Demo() for i in d: print(i) 运行结果: [1, 2, 3] [1, 2, 3] [1, 2, 3] [1, 2, 3] [1, 2, 3] ...
class Demo: def __init__(self, x): self.x = x self.count = 1 def __iter__(self): # 只要重写iter方法就是可迭代对象 return self def __next__(self): # 每一次for...in都会调用一次next方法,获取返回值 if self.count <= self.x: self.count += 1 return 'hello world' else: raise StopIteration # 停止迭代 d = Demo(4) for x in d: print(x) # hello world # hello world # hello world # hello world d.__iter__().__next__() # 对象迭代简单化
6、判断对象是不是迭代器
names=['zhangsan','lisi'] print(names.__iter__()) #调用方法 print(iter(names)) #调用函数
from collections.abc import Iterator names=['zhangsan','lisi'] print(isinstance(iter(names), Iterator)) #True
二、生成器
1、创建生成器方法
a、把列表推导式的【】改成()
#列表推导式
l = [x ** 2 for x in range(5)] print(l) # [0, 1, 4, 9, 16]
#生成器 g=(x**2 for x in range(5)) print(g) #<generator object <genexpr> at 0x0000000001D1FA20> print(next(g)) #0 print(next(g)) #1 print(next(g)) #4 print(next(g)) #9 print(next(g)) #16 print(next(g)) #非正常退出 #for x in g: # print(x) #运行结果: #0 #1 #4 #9 #16
b、使用函数实现
def my_gen(n): i = 1 while i < n: print('hello') yield i i += 1 print('world') g = my_gen(4) print(next(g)) print(next(g)) print(next(g)) print(next(g)) # StopIteration # hello # 1 # world # hello # 2 # world # hello # 3 # world
def foo():
print('starting...')
while True:
res = yield 'hello world'
print('closing...',res)
g = foo()
print(next(g))
print('*' * 10)
print(next(g))
# starting...
# hello world
# **********
# closing... None
# hello world
a、程序开始执行以后,因为foo函数中有yield关键字,所以foo函数并不会真的执行,而是先得到一个生成器g(相当于一个对象)
b、直到调用next方法,foo函数正式开始执行,先执行foo函数中的print方法,然后进入while循环
c、程序遇到yield关键字,然后把yield想成return,return了一个'hello world'之后,程序停止,并没有执行赋值给res操作,此时next(g)语句执行完成,所以输出的前两行(第一个是while上面的print的结果,第二个是return出的结果)是执行print(next(g))的结果
d、程序执行print("*"*10),输出10个*
e、又开始执行下面的print(next(g)),这个时候和上面那个差不多,不过不同的是,这个时候是从刚才那个next程序停止的地方开始执行的,也就是要执行res的赋值操作,这时候要注意,这个时候赋值操作的右边是没有值的(因为刚才那个是return出去了,并没有给赋值操作的左边传参数),所以这个时候res赋值是None,所以接着下面的输出就是closing...None
f、程序会继续在while里执行,又一次碰到yield,这个时候同样return 出'hello world',然后程序停止,print函数输出的'hello world'就是这次return出的'hello world'
3、总结
-
使用了yield关键字的函数不再是函数,而是生成器。(使用了yield的函数就是生成器)
- yield关键字有两点作用:
保存当前的运行状态(断点),然后暂停执行,即将生成器(函数)挂起
- 可以使用next()函数让生成器从断点处继续执行,即唤醒生成器(函数)
除了可以使用next()函数来唤醒生成器继续执行之外,还可以使用send()函数来唤醒执行,使用send()函数的一个好处是可以在唤醒的同时向断点处传入一个附加数据。
def gen(): i = 0 while i < 5: temp = yield i print(temp) i += 1 f = gen() print(next(f)) f.send('hello') # 唤醒生成器,并传值 print(next(f))
# 0 # hello # None # 2