Python 生成器

Python中一边循环一边计算的机制称为生成器,即generator。在generator中记录了获取下一个对象的算法,当我们需要数据的时候就可以通过生成器去获取,而不需要事先存储这些数据,以免浪费资源。

一、创建生成器的两种方法

(1)使用"()"来生成,将列表推导式中的"[ ]"改为"()"即可

# 创建生成器对象nums
nums = (x for x in range(5))

print("nums的类型:", type(nums))  
# 输出: <class 'generator'>

# 遍历生成器,使用next() 或者 for...in...
# next() 方法一次获取一个,当取到最后一个之后,再次获取抛出异常:StopIteration

print(next(nums))
# 输出: 0

for i in nums:
    print(i) 

# 输出: 0 1 2 3 4

(2)使用函数来实现生成器,在函数需要的地方使用yield,这样函数就变成了一个生成器对象,此时调用函数的返回值就是一个生成器对象,如下示例:

# 通过函数实现生成器对象

def generator_e():
    x = 2
    while True:
        y = 3 * x + 1
        x = y
        yield y  # 将函数改变为一个生成器对象

# 调用函数,则函数返回值是一个generator
var = generator_e()

print("var的类型:", type(var))
# 输出:var的类型: <generator object generator_e at 0x000001DD4C77AB88>

# 对该对象同样可以使用next()和for...in...来遍历(二者区别是:若是无数量限制,for循环会
# 一直往下执行)
print(next(var))

i = 0
for item in var:
    i += 1
    if i == 6:  
        break
    print(item)

二、生成器中的yield的执行原理

如果是第一次对生成器使用next(),则从def 函数代码块的部分开始执行,直到遇到yield时停止,并且把yield关键字后的数值当做调用next()的返回值,如果不是第一次,则从上一次暂停的位置继续往下执行直到遇到下一次yield为止,同样把yield关键字后的数值返回,如下示例代码:

def generator_i():
    x = 1
    count = 1
    while True:
        y = 3 * x + 1
        x = y
        print("yield 执行前,第%d次调用next函数:"%count)        
        yield y  # 将函数改变为一个生成器对象
        count += 1
        print("yield 执行, 此时count的值为: %d"%count)

var = generator_i()

print(next(var))
>> yield 执行前,第1次调用next函数:
>> 4

print(next(var))
>> yield 执行, 此时count的值为: 2
>> yield 执行前,第2次调用next函数:
>> 13

print(next(var))
>> yield 执行, 此时count的值为: 3
>> yield 执行前,第3次调用next函数:
>> 40

三、生成器中send()方法

从前面可知,我们可以通过next()方法让生成器继续往下执行,获取下一个元素。在Python中,我们还可以使用send()方法来让生成器往下执行,send()方法的另一个优点是让我们主动向生成器发送数据。使用send()方法的基本格式是:xxx = yield yyy(只需将yield 语句"赋值"给某个对象即可,执行过程中,send会让生成器从上次停止的位置继续往后执行,并且会将传入的参数传递到生成器中)

def generator_m():
    while True:
        print("***** *_* *****")
        strf= yield 100  # 此处可以通过send()传值,如果不传值则下一次
                         # 开始执行会将None赋值给strf
        print("*——*","strf = ", strf)

g = generator_m()  # 生成器对象

print(next(g))
>> ***** *_* *****
>> 100

print(g.send("第一次调用send方法给num传值"))  # 将这个值传递给strf参数,并
                                     # 继续往后执行直到遇到yield
>> *——* strf =  第一次调用send方法给num传值
>> ***** *_* *****  
>> 100

print(next(g))
>> *——* strf =  None
>> ***** *_* *****
>> 100

需要注意的是如果是第一次使用生成器,不能直接使用send(参数)方式来获取下一个数据,需要使用next()或者使用send(None)启动生成器,如下例:

def generator_n():
    while True:
        print("* *_* **")
        strf = yield 100
        print("*——*", "strf = ", strf)

n_n=  generator_n()

# 直接传参或者不传参
n_n.send("00000"
>> TypeError: can't send non-None value to a just-started generator
>> TypeError: send() takes exactly one argument (0 given)

# 传参None 或者 使用 next(n_n)
print(n_n.send(None))
>> * *_* **
>> 100

# 继续传参
print(n_n.send(1))
>> *——* 1
>> * *_* **
>> 100

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值