from icecream import ic
import time
import sys
import collections.abc
# time.clock() # 获取cpu开始工作的时间。time.clock()在python3已经不推荐使用了,在python3.8中被废除了。
t1 = time.time()
ic([i for i in range(1, 18) if i % 2 == 0]) # 有判断条件,耗时长。列表是一次性全部生成数据
costTime = time.time()-t1
print('耗时:%g' % costTime) # 耗时:0.906052。%g:指数(e)或浮点数(根据显示长度)
'''
在Python中,一边循环一边计算的机制,称为生成器(Generator)。生成器保存的是算法。
生成器是用来推算列表元素的,通过列表生成式,我们可以直接创建一个列表。
但是,受到内存限制,列表容量肯定是有限的。如果创建一个包含100万个元素的列表,会占用很大的存储空间。
而我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,我们可以在循环的过程中不断推算出后续的元素。
这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
所以生成器是为了生成列表时节省储存空间的产物,这样生成器会销毁也就不难理解了
'''
# 生成器是一种特殊的迭代器
t2 = time.time()
# 生成器的生成方式一:括号()。将列表生成式的[]改成()
g = (i for i in range(2, 28, 2))
print(g) # <generator object <genexpr> at 0x0000000009E80190> 生成器对象
print(sys.getsizeof(g)) # 112 生成器内存开销112个字节
print(type(g)) # <class 'generator'> 类型为生成器
print(isinstance(g, collections.abc.Iterable)) # True 生成器是可迭代对象
print(g.send(None)) # 2 # 使用send()方法访问时,若访问生成器的第一个元素,需传入参数'None', 访问其余元素时,可任意传参。
print(next(g)) # 4 法一:用next方法访问生成器的下一个元素
print(g.__next__()) # 6 法二:用.__next__()方法访问生成器的下一个元素
print(next(g)) # 8
print(g.__next__()) # 10
print(g.send('abc')) # 12 使用send()方法访问时,若访问生成器的第一个元素,需传入参数'None', 访问其余元素时,可任意传参。
print(g.send(None)) # 14 send()方法访问其余元素时,可任意传参。
for i in g: # 用for循环遍历访问余下的内容
print(i, end=' ')
print('\n')
ic(i for i in range(2, 18, 2)) # 生成器(记录算法),一边循环一边计算
ic([i for i in range(2, 18, 2)]) # 列表
ct2 = time.time()-t2
print('耗时:%g' % ct2)
print([a+b for a in '123' for b in 'xyz'])
# 生成器的生成方式二:函数中使用yield关键字。
'''一个带有 yield 的函数就是一个 generator,它和普通函数不同,生成一个 generator 看起来像函数调用,但不会执行任何函数代码,
直到对其调用 next()(在 for 循环中会自动调用 next())才开始执行。虽然执行流程仍按函数的流程执行,
但每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。
看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。
yield 的好处是显而易见的,把一个函数改写为一个 generator 就获得了迭代能力,
比起用类的实例保存状态来计算下一个 next() 的值,不仅代码简洁,而且执行流程异常清晰。'''
def func1(): # 带有 yield 的函数在 Python 中被称之为 generator(生成器)
for i in range(5):
yield i
# yield就是 return 返回一个值,并且记住返回的位置,下次迭代就从该位置开始。
f1 = func1()
print(type(f1)) # <class 'generator'>
print(next(f1)) # generator保存的是算法,每次调用next(),就计算出下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
print(f1.__next__())
print(next(f1))
print(f1.__next__())
print(f1.send('abc'))
print(next(f1)) # 超出范围,导致停止。
def func2(): # 带有 yield 的函数在 Python 中被称之为 generator(生成器)
for i in range(5):
pass
f2 = func2() # Function 'func2' doesn't return anything
print(type(f2)) # <class 'NoneType'>
python生成器
最新推荐文章于 2025-05-06 13:55:58 发布