一、偏函数
当我们向减少函数的参数时,我们可以用functools.partial(函数名,参数)来实现
import functools
def func(a,b,c):
return a + b + c
new_func = functools.partial(func,1)
result = new_func(2,3)
print(result)
# 输出结果
# 6
问题:设置一个基点(3,4),求点(1,2),(3,4),(5,6),(7,8)离基点的距离顺序的排序
import math
points = [(1,2),(3,4),(5,6),(7,8)]
def distance(point1,point2):
x1,y1 = point1
x2,y2 = point2
return math.hypot(x2 - x1,y2 - y1)
points.sort(key = functools.partial(distance,(3,4)))
print(points)
# 输出结果
# [(3, 4), (1, 2), (5, 6), (7, 8)]
二、协程函数
用async修饰的函数实协程函数,调用这个函数会返回一个协程对象,但不会执行函数体,若想要执行协程对象,有多种方法,第一个是send()方法
async def run1():
print(1)
print(2)
async def run2():
print(3)
print(4)
r1 = run1()# 获得一个协程对象
r2 = run2()
r1.send(None)
r2.send(None)
# 输出结果
# 1
# 2
# 报错StopIteration
报错的原因是,send方法会执行到下一个yield,但是协程中并没有,所以这种执行协程的方法不太推荐
三、await关键字与事件循环
- 事件循环:可以理解成一个死循环,一个列表里装着待执行的事件,每次遍历这个列表,找出可执行的事件和不可执行的事件,不可执行的事件包括在等待中阻塞的事件和已经完成的事件,遍历多次,直到列表里的事件全部执行完成为止,获取事件循环需要导入asyncio模块。
- await后面根一个可等待对象,1例如future,task,协程。作用是等待await后面根的那个对象执行完成之后再往后执行。
import asyncio
async def run1():
print(1)
await r2
print(2)
async def run2():
print(3)
print(4)
r1 = run1()
r2 = run2()
eventloop = asyncio.get_event_loop()
eventloop.run_until_complete(r1)
# 输出结果
#
# 1
# 3
# 4
# 2
r1运行,输出1,之后等待r2运行,输出1,2,r2运行完成,事件循环将会再次循环一次,r1继续执行,输出2,再循环一次,检测到事件运行完成,退出循环。
- task任务
由于协程对象不能直接运行,所以run_until_complete()是先将括号中的协程包装成task对象再运行,我们也可以手动获得这个对象。
import asyncio
async def run1():
print(1)
await r2
print(2)
async def run2():
print(3)
print(4)
r1 = run1()
r2 = run2()
eventloop = asyncio.get_event_loop()
task = eventloop.create_task(r1)
eventloop.run_until_complete(task)
# 输出结果
#
# 1
# 3
# 4
# 2
也可以通过task获取协程运行后的结果
print('result = ',task.result())
因为我们定义的协程没有任何返回值,所以输出result = None
- 通过回调函数获取返回值。
什么是回调函数?
- 当程序跑起来时,一般情况下,应用程序(application program)会时常通过API调用库里所预先备好的函数。但是有些库函数(library function)却要求应用先传给它一个函数,好在合适的时候调用,以完成目标任务。这个被传入的、后又被调用的函数就称为回调函数(callback function)。
- 打个比方,有一家旅馆提供叫醒服务,但是要求旅客自己决定叫醒的方法。可以是打客房电话,也可以是派服务员去敲门,睡得死怕耽误事的,还可以要求往自己头上浇盆水。这里,“叫醒”这个行为是旅馆提供的,相当于库函数,但是叫醒的方式是由旅客决定并告诉旅馆的,也就是回调函数。而旅客告诉旅馆怎么叫醒自己的动作,也就是把回调函数传入库函数的动作,称为登记回调函数
import asyncio
async def run1():
print(1)
await r2
print(2)
return 'stop'
async def run2():
print(3)
print(4)
def callback(future):# 定义回调函数
print('callback:',future.result())
r1 = run1()
r2 = run2()
eventloop = asyncio.get_event_loop()
task = asyncio.ensure_future(r1) # 获取task对象
task.add_done_callback(callback)# 绑定回调函数
eventloop.run_until_complete(task)
# 输出结果
#
# 1
# 3
# 4
# 2
# callback: stop
- 利用asyncio协程完成并发
import asyncio
async def run():
print(1)
await asyncio.sleep(1)
print(2)
return 'stop'
tasks = [asyncio.ensure_future(run()),
asyncio.ensure_future(run()),
asyncio.ensure_future(run())]
eventloop = asyncio.get_event_loop()
eventloop.run_until_complete(asyncio.wait(tasks))
# 输出结果
#
# 1
# 1
# 1
# 2
# 2
# 2