一.问题引入
在Python中,可以使用生成器来一次返回单个元素,从而可以避免大量占用内存。下面例子中计算房价函数house_price
便是一个生成器的栗子,该函数接收两个参数,其中unit_price
表示每平方米单价,areas
是售卖的房子的面积。
def house_price(unit_price ,areas):
for area in areas:
yield unit_price * area
unit_price = 1
areas = [100, 120, 110, 180]
for price in house_price(unit_price, areas):
print(f"Price: {price}")
"""
Price: 100
Price: 120
Price: 110
Price: 180
"""
但是上述函数无法解决一个问题:在生成器调用的过程中,我们想更改计算房价的每平方米单价。因此我们需要一种方法可以更改生成器每次迭代的unit_price
参数值,这个需求可以做到吗?但是的肯定可以。生成器的send()
方法就可以解决这个问题。
二.send()方法详细介绍
生成器的send()
方法可以往生成器发送一个值并返回生成器生成的下一个值,下面举个简单的栗子来简单介绍下该方法。
def my_generator():
receive = yield 3
yield f"{receive}"
myg = my_generator()
print(myg.send(None)) # print(next(myg))与其作用是等同的
# 3
print(myg.send(5))
# 5
首先,解释下receive = yield 3
这行代码,这行代码可以拆成两部分来看,即yield 3
和receive = yield
,前者表示生成一个新的值,后者指接收send()
方法传过来的值。在执行顺序上,调用send()
方法后会先yield 3
,当再次调用next()
方法时才会完成receive
的赋值。
send()方法会引发一次
next()
方法的调用。
然后,再解释下为啥需要myg.send(None)
,这是send()
方法的低层实现硬性规定的,当首次执行时不允许带有参数,下面的对应该部分的低层源码:
if (f->f_lasti == -1) { // f_lasti==-1 代表首次执行
if (arg && arg != Py_None) { // 首次执行不允许带有参数
PyErr_SetString(PyExc_TypeError,
"can't send non-None value to a "
"just-started generator");
return NULL;
}
}
在上述栗子中,若去掉myg.send(None)
,则会报错:TypeError: can't send non-None value to a just-started generator
。
三.问题解决
有了send()
方法,我们现在给出第一节中问题的解决方案:
def house_price(areas):
unit_price = yield # 接收初始的unit_price
for area in areas:
unit_price = yield unit_price * area
unit_prices = [1, 2, 3, 1]
areas = [100, 120, 110, 180]
hp = house_price(areas)
hp.send(None) # 启动生成器
for unit_price in unit_prices:
cur_price = hp.send(unit_price)
print(f"Price: {cur_price}")
"""
Price: 100
Price: 240
Price: 330
Price: 180
"""
可以看到通过send()
方法,我们可以为每个交易指定一个房价。
结语
从前面的介绍可以看出:send()
方法提供了调用者与生成器间的通信机制,通过该机制我们可以进行一些特殊操作,当然这也要视需求而定。
参考资料:
以上便是本文的全部内容,要是觉得不错的话,可以点个赞或关注一下博主,你们的支持是博主创作的不竭动力,当然要是有问题的话也敬请批评指正!!!