python的异步第一依赖注入库
aiodine的Python项目详细描述
艾奥丁
aiodine以python 3.6+的pytest fixtures的方式,首先提供异步依赖注入。
安装
pip install aiodine
概念
艾奥丁围绕两个概念展开:
- 提供者负责设置、返回和选择性地清理资源
- 消费者可以通过将提供者声明为其参数之一来访问这些资源。
这种方法是依赖注入的实现,使得提供者和消费者:
- 显式:根据消费者签名上的名称引用提供者,使依赖关系清晰且可预测。
- 模块化:提供者本身可以使用其他提供者,允许构建可重用(和可替换)依赖关系的生态系统。
- 灵活:提供的值在给定的范围内重用,提供者和使用者支持各种语法(异步/同步、函数/生成器)以使资源调配再次变得有趣。
aiodine首先是异步的
- 它是用来处理协同程序函数和异步/等待语法的。
- 只能在异步设置中调用使用者。
- 但是提供者和使用者函数也可以是常规的python函数和生成器,如果只是为了方便的话。
用法
提供者
提供者在特定范围内为消费者提供资源。它们是通过用@aiodine.provider
这里有一个"Hello World"提供商:
importaiodine@aiodine.providerasyncdefhello():return"Hello, aiodine!"
提供程序有两个作用域:
函数
:提供程序的值在每次使用时都会重新计算。会话
:提供者的值只计算一次(第一次使用时),并在随后的调用中重复使用。
默认情况下,提供者是功能范围的。
消费者
一旦声明了提供者,它就可以被消费者使用。consumer是通过用@aiodine.consumer
装饰一个consumer函数来构建的。使用者可以将提供者声明为其参数之一,并且aiodine将在运行时注入它。
下面是一个消费者示例:
@aiodine.consumerasyncdefshow_friendly_message(hello):print(hello)
所有aiodine使用者都是异步的,因此您需要在异步上下文中运行它们:
fromasyncioimportrunasyncdefmain():awaitshow_friendly_message()run(main())# "Hello, aiodine!"
当然,使用者也可以声明非提供者参数。aiodine足够聪明,能够确定哪些参数应该通过提供者注入,哪些应该从被调用方获得。
@aiodine.consumerasyncdefshow_friendly_message(hello,repeat=1):for_inrange(repeat):print(hello)asyncdefmain():awaitshow_friendly_message(repeat=10)
使用其他提供商的提供商
提供商是模块化的,因为他们自己可以使用其他提供商。
但是,要使其正常工作,必须首先冻结提供者。这可确保无论申报顺序如何,依赖关系图都能正确解析。
importaiodine@aiodine.providerdefemail():return"user@example.net"@aiodine.providerasyncdefsend_email(email):print(f"Sending email to {email}…")aiodine.freeze()# <- Ensures that `send_email` has resolved `email`.
注意:可以安全地多次调用.freeze()
。
上下文管理器语法也可用:
importaiodinewithaiodine.exit_freeze():@aiodine.providerdefemail():return"user@example.net"@aiodine.providerasyncdefsend_email(email):print(f"Sending email to {email}…")
发电机供应商
生成器提供程序可用于在提供程序超出范围后执行清理(终结)操作。
importosimportaiodine@aiodine.providerasyncdefcomplex_resource():print("setting up complex resource…")yield"complex"print("cleaning up complex resource…")
提示:即使使用者中发生异常,也会执行清除代码,因此无需用try/finally
块包围yield
语句。
重要信息:只有在会话上下文中使用会话范围的生成器提供程序时,才会清除它们。有关详细信息,请参见会话。
延迟异步提供程序
默认情况下,异步提供程序是急切的:它们的返回值在注入到使用者之前等待。
您可以将提供程序标记为懒惰,以便推迟等待提供给消费者的值。这在需要有条件地评估提供者时非常有用。
fromasyncioimportsleepimportaiodine@aiodine.provider(lazy=True)asyncdefexpensive_io_call():awaitsleep(10)return42@aiodine.consumerasyncdefcompute(expensive_io_call,cache=None):ifcache:returncachereturnawaitexpensive_io_call
工厂供应商
工厂提供程序返回一个函数,而不是返回一个标量值。工厂提供程序有助于实现可重用的提供程序,以接受各种输入。
< Buff行情>这是一个设计模式。事实上,aiodine中没有额外的代码支持此功能。
以下示例为(模拟)数据库查询定义了工厂提供程序:
pip install aiodine
0
消费者中的示例用法:
pip install aiodine
1
提示:您可以将工厂提供程序与发电机提供程序结合使用,以清除工厂需要使用的任何资源。下面是一个提供临时文件并在清理时将其删除的示例:
pip install aiodine
2
使用提供程序而不将其声明为参数
有时,消费者需要使用提供者,但并不关心它返回的值。在这些情况下,您可以使用@useprovider
装饰符并跳过将其声明为参数。
提示:useprovider装饰器接受可变数量的提供程序,这些提供程序可以按名称或引用给定。
pip install aiodine
3
自动使用的提供商
自动使用的提供程序将自动激活(在其配置的范围内),而无需在使用者中将其声明为参数。
这通常可以让你免于装饰你所有的房间带有@useprovider的ers
例如,下面的自动使用提供程序将导致每次调用消费者时都将当前日期和时间打印到控制台。
pip install aiodine
4
会话
a会话是会话提供程序实时运行的上下文。
更具体地说,会话提供者(resp.生成器会话提供程序)已实例化(分别为安装程序)进入会话时,并销毁(resp.(已清理)退出会话时。
要进入会话,请使用:
pip install aiodine
5
退出:
pip install aiodine
6
异步上下文管理器语法也可用:
pip install aiodine
7
上下文提供程序
< Buff行情>警告:这是一项实验性功能。
引入上下文提供者解决了上下文本地资源的注入问题。这些资源在提供者声明时通常是未定义的,但在输入某种上下文时会变得定义良好。
这听起来可能很抽象,因此在显示上下文提供程序的用法之前,让我们先看一个示例。 假设我们在餐厅。在那里,服务员执行顾客提交的订单。每个客户都有一个 在aiodine术语中,服务生是订单的提供者,客户是消费者。
在服务过程中,服务员需要倾听新客户的声音,创建一个新的 因此,在本例中,上下文的范围从订单创建到订单销毁,并且特定于给定的客户。 下面是在服务生方面模拟这种情况的代码: 需要注意的是,客户可以对订单执行任何操作。特别是,他们可能需要一些时间来考虑他们要点什么。同时,服务器将监听其他客户的呼叫。从这个意义上讲,这种情况是异步的。 示例客户代码可能如下: 让我们考虑一下这个问题。你注意到服务员只拿着一份订单吗?这意味着只要每次只为一个客户提供服务,代码就可以正常工作。 但是如果另一个客户,比如说,当爱丽丝在考虑她要点什么的时候,出现了,怎么办?在当前的实现中,服务生只需忘记 通过使用上下文提供程序,我们透明地将服务生的 下面是代码的外观:示例
顺序
对象,他们可以
.write()
将所需的菜单项发送到该对象。订单
对象,将其提供给客户,执行客户编写的订单,并销毁已执行的订单。
8
pip install aiodine
9
pip install aiodine
alice的订单,并最终执行
bob的订单两次。简而言之:我们将遇到一个竞赛条件
订单
转换为上下文变量(a.k.a.contextvar
)。它是每个客户的本地上下文,可解决比赛条件。importaiodine@aiodine.providerasyncdefhello():return"Hello, aiodine!"
0
注:
- 客户可以像以前一样使用
订单
提供商。实际上,它是在调用
时创建的。create_context_provider()
订单现在是本地上下文,即如果其他客户同时来订购,它的价值不会被遗忘或扰乱。
这种情况在某些人看来可能微不足道,但在客户机/服务器体系结构(包括web框架)中可能会发现。
用法
要创建上下文提供程序,请使用aiodine.create_context_provider()
。此方法接受可变数量的参数并返回contextprovideR < /代码>。每个参数都用作一个新的provider的名称,该provider提供了a
contextvar
对象的内容。
importaiodine@aiodine.providerasyncdefhello():return"Hello, aiodine!"1
每个上下文变量最初都包含none
。这意味着消费者将收到none
-除非在的上下文中调用它们。assign()
块:
importaiodine@aiodine.providerasyncdefhello():return"Hello, aiodine!"2
FAQ
为什么叫"爱奥丁"?
aiodine包含"aio",如异步中的"aio"和依赖注入中的"di"。最后两个字母的发音类似于化学元素碘。
更改日志
许可证
麻省理工学院< /P>