跳转至

如何使用Pait装饰器

在使用Pait的过程中,可能会发现有多个路由函数使用到参数配置是相同的,如下代码:

from pait.app.any import pait
from pait.model.status import PaitStatus

@pait(status=PaitStatus.test)
def demo1() -> None:
    pass


@pait(status=PaitStatus.test)
def demo2() -> None:
    pass

@pait(status=PaitStatus.test)
def demo3() -> None:
    pass

示例代码中共有3个路由函数,由于他们还处于测试阶段,所以它们status的值都是PaitStatus.test。 在经过一段时间的测试后,代码已经变得完善了并且可以准备发布,此时路由函数的状态需要变更为Relese, 于是就得手动的把每个路由函数的状态都切换为PaitStatus.release, 在路由函数比较多的时候,手动的切换状态是非常麻烦的。 为此,可以先定义一个公共的Pait并在所有路由函数使用,使这些路由函数可以共享同一个Pait,从而共享同一份配置功能。

Note

  • 1.本章节提供的示例都是基于Starlette框架,其他框架在使用的时候只有导入Pait类的import语句稍有不同外。
  • 2.本章节着重介绍的是Pait类的用法,不同属性的作用会在其对应的文档介绍。
  • 3.Pait可以认为是一个托管数据的容器,只要他们的属性一致,那么他们的功能是一致的,即使他们之间没有任何关系。

1.自定义Pait

在前文关于Pait的介绍,都是通过如下语法导入Pait:

from pait.app.flask import pait
from pait.app.sanic import pait
from pait.app.starlette import pait
from pait.app.tornado import pait

通过该语法导入的pait是每个Web框架对应Pait类的单例,在自定义Pait时,建议通过Web框架对应的Pait类入手,比如下面的示例代码:

from pait.app.starlette import Pait
from pait.model.status import PaitStatus
from starlette.responses import Response


global_pait: Pait = Pait(status=PaitStatus.test)

@global_pait()
async def demo() -> Response:
    pass


@global_pait()
async def demo1() -> Response:
    pass


@global_pait()
async def demo2() -> Response:
    pass
示例代码的第一段高亮代码是基于Pait类创建一个名为global_paitPait实例,它与框架对应pait实例类似,唯一的区别是它的status属性被指定为PaitStatus.test。 其他高亮代码则是把global_pait都应用到所有的路由函数中,路由函数的status与下面这段代码的status是一致的:
@pait(status=PaitStatus.test)
async def demo() -> Response:
    pass

2.创建子Pait

Pait可以通过create_sub_pait方法创建自己的子Pait,每个子Pait的属性都是从父Pait克隆的,比如下面这段代码:

from pait.app.starlette import Pait
from pait.model.status import PaitStatus

global_pait: Pait = Pait(status=PaitStatus.test)
other_pait: Pait = global_pait.create_sub_pait()
代码中other_pait是通过global_pait创建的,所以它的status属性也跟global_paitstatus属性一样都是PaitStatus.test

如果不想克隆父Pait的属性,那么可以在创建子Pait时指定子Pait的属性,从而达到覆盖父Pait属性的效果,如下代码:

from pait.app.starlette import Pait

global_pait: Pait = Pait(author=("so1n",), group="global")
user_pait: Pait = global_pait.create_sub_pait(group="user")
global_paituser_paitauthor属性都为("so1n", ), 但是由于在创建user_pait时指定了group的值为user,所以global_paituser_paitgroup属性是不同的,它们分别为globaluser

3.使用Pait

Pait的用法与标准pait装饰器的用法是完全一致的,唯一不同的是它本身已经携带了部分配置数据,在装饰路由之后,会使路由函数拥有了对应的配置功能。如下代码:

from pait.app.starlette import Pait
from starlette.responses import JSONResponse

global_pait: Pait = Pait(author=("so1n",), group="global")
user_pait: Pait = global_pait.create_sub_pait(group="user")


@user_pait()  # group="user"
async def user_login() -> JSONResponse:
    pass

@user_pait()  # group="user"
async def user_logout() -> JSONResponse:
    pass

@global_pait()  # group="global"
async def get_server_timestamp() -> JSONResponse:
    pass
路由函数user_loginuser_logout都被user_pait装饰, 所以他们的group的值都为user; 而路由函数get_server_timestampglobal_pait装饰,所以它的group的值为global

此外,在子pait装饰路由函数时,可以通过定义属性的值实现覆写子pait原先的属性值。 如下面的代码,高亮代码中的路由函数的user_logoutgroup属性变为user-logout而不再是user:

from pait.app.starlette import Pait
from starlette.responses import JSONResponse

global_pait: Pait = Pait(author=("so1n",), group="global")
user_pait: Pait = global_pait.create_sub_pait(group="user")


@user_pait()
async def user_login() -> JSONResponse:
    pass

@user_pait(group="user-logout")
async def user_logout() -> JSONResponse:
    pass

@global_pait()
async def get_server_timestamp() -> JSONResponse:
    pass

除了覆盖原有的值外,部分属性还支持追加值,如下代码:

from pait.app.starlette import Pait
from starlette.responses import JSONResponse

global_pait: Pait = Pait(author=("so1n",), group="global")
user_pait: Pait = global_pait.create_sub_pait(group="user")


@user_pait()  # group="user"
async def user_login() -> JSONResponse:
    pass


@user_pait(append_author=("Other Author",))  # group="user"; author=("so1n", "Other Author",)
async def user_logout() -> JSONResponse:
    pass


@global_pait()  # group="global"
async def get_server_timestamp() -> JSONResponse:
    pass
高亮部分代码中使用到了Paitappend_xxx系列的参数来追加值,从而使user_logoutauthor值变为("so1n", "Other Author")

Note

追加的值只会添加到序列中的末尾,而部分功能如Pre-Depend需要考虑值的放置顺序,使用时请留意追加的顺序是否合适。