2023年7月10日发(作者:)
python基础:泛型Generic的坑-注意它只是提⽰符,⽽不能真正schema⽬录
前⾔在写项⽬的时候,我实现了⼀个泛型容器,希望能够⽤来兼容多个实体的shema。但是这时候出问题了,我发现通过Generic容器传⼊的schema参数并没有什么⽤?这是为什么呢?原因就在于:泛型只是⼀个hint,可以帮助提⽰你应该输⼊什么类型的参数以及可以提⽰ID E此处应该传⼊什么参数,从⽽提醒你是否出错的参数。但是泛型(包括typing⾥的所有变量)并⽆法帮助你完成schema的功能。所以,我当初就是没有意识到这⼀点,才傻傻的去实现,结果没有任何作⽤,但是我⼜找到⼀种⽅法,可以拿到Generic容器中的类。⼀、证明Generic⽆法shema我们这⾥看⼀个简单的程序,然后最后我会贴出我项⽬中遇到的问题,并且是怎样解决的。from typing import TypeVar, TypeT = TypeVar('T')class Test(Generic[T]): def hello(self): my_type = T # this is wrong! print( "I am {0}".format(my_type) )Test[int]().hello()# should print "I am int"# however, it prints "I am ~T"上⾯代码输出了 "I am ~T",很意外。下⾯代码会证明它⽆法schemafrom typing import Generic, TypeVarfrom pydantic import BaseModelclass ModelSchema(BaseModel): name: str age: intModel = TypeVar("Model", bound=BaseModel)class CRUDBase(Generic[Model]): def print_type(a: Model): print(a) print(type(a))class Service1(CRUDBase[ModelSchema]): _type(18)如果schema管⽤的话,_type()⾥应该传⼊⼀个ModelSchema类型的参数,否则就会报错。但是当我⽤这段代码去运⾏时,仍然可以正常运⾏且输出结果,如下:但是,在ID E中输⼊ _type(18) 时, ID E会提醒你,你应该传⼊⼀个ModelSchema类型的参数,这就是typing hint的作⽤。但是,它并⽆法起到schema的作⽤。
⼆、项⽬中遇到了什么问题,怎么解决的我在⽤FastAPI写⼀个后端项⽬,平时呢,我都是⽤Pydantic的BaseModel写好了schema,然后协程如下的形式来进⾏schema。直接就可以schema住。from pydantic import BaseModelfrom fastapi import APIRouterfrom import HTTP_201_CREATEDclass PersonSchema(BaseModel): name: str age: int@("/", status_code=HTTP_201_CREATED)def create(*, params: PersonSchema): pass但是,在些项⽬的时候,发现每个接⼝都会有⼀套针对数据库的CRUDAPI,也就是post、get、put、delete四种。那么我就想写⼀个CRUDBaseAPI的类,所有要实现这类CRUD API的需求,只需要调⽤⼀下CRUDBaseAPI就可以完成,这样就可以剩下很多的代码了。于是,我就使⽤如下⽅式实现:from typing import TypeVar, Genericfrom fastapi import APIRouter, Dependsfrom pydantic import BaseModelModel = TypeVar("Model", bound=BaseModel)CreateSchema = TypeVar("CreateSchema", bound=BaseModel)UpdateSchema = TypeVar("UpdateSchema", bound=BaseModel)class CRUDServiceBase(Generic[Model,CreateSchema,UpdateSchema]): @classmethod def register(cls, router:APIRouter,crud:CRUDBase): @("/", response_model=Model): def create(*, database=Depends(connection), params:CreateSchema): pass
@("/", response_model=Model): def read(*, database=Depends(connection)): pass
@("/", response_model=Model): def update(*, database=Depends(connection), params:UpdateSchema): pass
@("/", response_model=Model): def delete(*, database=Depends(connection)): pass return router这样,当我写⼀个类集成CRUDServiceBase就可以定制⼀个拥有CRUDAPI的接⼝了。如下class CRUDEntityAPI(CRUDServiceBase[Entity, CreateEntitySchema,UpdateEntitySchema]): passrouter = er(CRUDEntity)但是,这时候问题就出现了,因为所有的schema都不⽣效了,在调⽤⽣成的API时,即使我随便传⼊什么数据都是可以的,这肯定是不⾏的,因为shema失效,就没有意义了。那么怎么做呢,我只有将Generic中传⼊的shema实体再拿出来,传⼊到post、get等api的chema中才可以起作⽤。那么,怎么拿到Generic中的类对象呢?可以使⽤下⾯的⽅式。Generic中传⼊的类会记录再__orig_class__.__args__中,并且是⼀个元组self.__orig_class__.__args__[0] 代表取generic中第⼀个类,以此类推所以,我就有了⾃⼰的改造⽅案,可以正常schema住了,代码如下:from typing import TypeVar, Generic, Typefrom fastapi import APIRouter, Dependsfrom pydantic import BaseModelModel = TypeVar("Model", bound=BaseModel)CreateSchema = TypeVar("CreateSchema", bound=BaseModel)UpdateSchema = TypeVar("UpdateSchema", bound=BaseModel)class CRUDServiceBase(Generic[Model,CreateSchema,UpdateSchema]): @classmethod def api_model_type(cls) -> Type[Model]: return cls.__orig_class__.__args__[0]
@classmethod def api_create_type(cls) -> Type[CreateSchema]: return cls.__orig_class__.__args__[1]
@classmethod def api_update_type(cls) -> Type[UpdateSchema]: return cls.__orig_class__.__args__[2] @classmethod def register(cls, router:APIRouter,crud:CRUDBase): api_model = _model_type() api_create = _create_type() api_update= _update_type()
@("/", response_model=api_model): def create(*, database=Depends(connection), params:api_create): pass @("/", response_model=api_model): def read(*, database=Depends(connection)): pass @("/", response_model=api_model): def update(*, database=Depends(connection), params:api_update): pass @("/", response_model=api_model): def delete(*, database=Depends(connection)): pass return routerclass CRUDEntityAPI(CRUDServiceBase[Entity, CreateEntitySchema,UpdateEntitySchema]): passrouter = er(CRUDEntity)
发布者:admin,转转请注明出处:http://www.yc00.com/web/1688930740a184713.html
评论列表(0条)