Python 程序度量监测、数据验证的模块。如:
timeit:【标准库】运行时间效率测量,精细粒度级别pyheat:可视化显示运行时间,好像不太行,time.sleep(10) 都没检测出来profile:性能调优利器,定位性能/耗时瓶颈。memory_profiler:监控 python 进程的工具,加个装饰器即可输出每行代码内存使用情况pydantic:校验数据的工具typing:【标准库】类型标注支持timeit timeit:【标准库】运行时间效率测量,精细粒度级别
pyheat:可视化显示运行时间,好像不太行,time.sleep(10) 都没检测出来
1 2 3 4 5 6 import timeitdef test (): pass print (timeit.timeit('test()' , setup='from __main__ import test' ,number=1000 ))
profile profile:性能调优利器,定位性能/耗时瓶颈。
1 2 3 4 5 6 import profiledef test (): x=2 return x**2 profile.run('test' )
memory_profiler memory_profiler:监控 python 进程的工具,加个装饰器即可输出每行代码内存使用情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import timefrom memory_profiler import profile@profile def my_func (): a = [1 ] * (10 ** 6 ) b = [2 ] * (2 * 10 ** 7 ) time.sleep(10 ) del b del a print ("+++++++++" ) if __name__ == '__main__' : my_func()
1 2 3 mprof run test.py # 运行 mprof plot # 绘图 mprof clean # 清理
pydantic pydantic:校验数据的工具
功能:定义数据,自动校验与转换
定义数据:字段、类型、约束 自动类型转换:字符串 “1” 变成数字 1 一致错误格式:统一输出 易用:维护简单(加改字段改类属性即可),IDE还能自动提示 安全可读易维护 将数据的结构声明为具有属性的类,在创建这个类的实例时,值会被校验,并(在需要的情况下)转换为适当的类型,返回一个包含所有数据的对象。
它是一个解析库,不是验证库。验证是达到 建立一个符合所提供的类型 和约束的模型的手段。
保证的是输出数据的类型 与约束,而不是输入类型 虽然验 证不是它的主要目的,但可以用它进行自定义验证 可以更为规范地定义和使用数据接口,对于大型项目的开发更为友好
pydantic 在数据传输时会直接进行数据类型转换 ,因此,如果数据传输格式错误,但是可以通过转换变换为正确的数据类型是,数据传输也可以成功
优点
IDE 加成 类型注解定义类的实例 验证请求数据 ,从环境变量中读取系统设置 可以验证复杂结构,validator 装饰器 dataclass 装饰器,创建带有输出数据解析和验证的普通 Python 数据类 可递归使用:BaseModel 创建的作为类型 BaseModel+Field声明字段 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 from pydantic import BaseModelfrom typing import Dict ,List ,Sequence ,Set ,Tuple class Person (BaseModel ): name:str a: int b: float c: str d: bool e: List [int ] f: Dict [str , int ] g: Set [int ] h: Tuple [str , int ] p = Person(name="Tom" ) print (p.json()) print (p.model_dump()) print (p.model_dump_json()) p = {"name" : "Tom" } p = Person(**p) print (p.json()) class Person : def __init__ (self, name: str ): self .name = name def get_person_name (one_person: Person ): return one_person.name Person.parse_obj() Person.parse_raw() Person.parse_file() person.__fields_set__ person.dict () person.json() person.copy() person.parseobj() parseraw() 用于加载多种格式字符串的实用程序;参看。辅助函数 parsefile() 喜欢parseraw()但是对于文件路径;参看。辅助函数 fromorm() 将数据从任意类加载到模型中;参看。ORM模式 schema() 返回将模型表示为 JSON Schema 的字典;参看。图式 schemajson() schema()返回;的 JSON 字符串表示形式 参看。图式 construct() 无需运行验证即可创建模型的类方法;参看。创建没有验证的模型 - dict () - json() - copy() 模型的副本(默认为浅表副本) - parse_obj() 使用dict 解析数据 - parse_raw 将str 或bytes 并将其解析为json,然后将结果传递给`parse_obj` - parse_file 文件路径,读取文件并将内容传递给`parse_raw`。如果`content_type`省略,则从文件的扩展名推断 - from_orm() 从ORM 对象创建模型 - schema() 返回模式的字典 - schema_json() 返回该字典的 JSON 字符串表示 - construct() 允许在没有验证的情况下创建模型 - __fields_set__ 初始化模型实例时设置的字段名称集 - __fields__ 模型字段的字典 - __config__ 模型的配置类
Field 约束:范围 / 长度 / 正则 ge / le / gt / lt 类似数学比较:ge = >=,lt = < 正则 pattern 用来匹配格式(可简单理解为“形状过滤器”) description 方便后续生成文档 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from pydantic import BaseModel, Field, ValidationErrordef demo_field_constraints (): class Product (BaseModel ): name: str = Field(..., min_length=2 , max_length=30 , description="商品名称" ) price: float = Field(..., ge=0 , le=9999.99 , description="价格范围 0~9999.99" ) sku: str = Field(..., pattern=r"^[A-Z0-9]{6}$" , description="6位大写字母或数字" ) stock: int = Field(0 , ge=0 ) try : p = Product(name="电脑" , price="4999" , sku="AB12C3" , stock="10" ) print ("合法商品:" , p.model_dump()) except ValidationError as e: print ("错误:" , e.errors()) try : Product(name="X" , price=-1 , sku="abc123" ) except ValidationError as e: print ("约束错误:" , e.errors())
List[Item] 表示一个“里面全是 Item”的列表,会逐个校验default_factory=list 避免多个实例共用同一列表(经典坑)Dict[str, Any] 表示 key 是字符串,值随意Optional[T] = T 或 NoneUnion[A,B]:按声明顺序尝试匹配Enum:可读性好,不容易拼错Literal:值只能是列出的那些1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 from pydantic import BaseModel, ValidationErrorfrom enum import Enumfrom typing import Union , Optional , Literal def demo_union_literal_enum (): class Status (str , Enum): PENDING = "pending" DONE = "done" FAILED = "failed" class Msg (BaseModel ): id : int payload: Union [int , str ] flag: Optional [bool ] = None state: Status level: Literal ["low" , "medium" , "high" ] = "low" m1 = Msg(id =1 , payload="123" , state="pending" ) m2 = Msg(id =2 , payload="abc" , state=Status.DONE, level="high" ) print ("消息1:" , m1.model_dump()) print ("消息2:" , m2.model_dump()) try : Msg(id =3 , payload=1.5 , state="other" ) except ValidationError as e: print ("枚举错误:" , e.errors())
字段级定制校验:field_validator 这里让你“插手”字段处理流程:原始值进来 → 你清洗 / 检查 → 正常转换。
mode=”before”:在类型转换前运行(适合清洗原始数据) 返回值必须显式 return,否则后续链条拿不到值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 from pydantic import BaseModel, Field, ValidationError, field_validatorfrom typing import Optional def demo_field_validator (): class Person (BaseModel ): name: str age: int = Field(..., ge=0 , le=150 ) email: Optional [str ] = None @field_validator("name" , mode="before" ) def trim_name (cls, v ): if isinstance (v, str ): v = v.strip() if not v: raise ValueError("姓名不能为空" ) return v @field_validator("email" ) def check_email (cls, v ): if v is None : return v if "@" not in v: raise ValueError("邮箱格式错误" ) return v.lower() p = Person(name=" Alice " , age="30" , email="A@EXAMPLE.COM" ) print ("处理后:" , p.model_dump()) try : Person(name=" " , age=10 ) except ValidationError as e: print ("字段验证错误:" , e.errors())
模型整体逻辑校验:model_validator 当判断需要“看两个或多个字段关系”时,用模型级校验。
预备知识
用于“多个字段之间的关系”检查 mode=”after”:先完成字段解析,再整体判断 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from pydantic import BaseModel, ValidationError, model_validatordef demo_model_validator (): class Event (BaseModel ): title: str start_ts: int end_ts: int @model_validator(mode="after" ) def check_time (self ): if self .end_ts <= self .start_ts: raise ValueError("end_ts 必须大于 start_ts" ) return self e = Event(title="会议" , start_ts=10 , end_ts=20 ) print ("合法事件:" , e.model_dump()) try : Event(title="错误" , start_ts=5 , end_ts=5 ) except ValidationError as e: print ("模型级错误:" , e.errors())
计算属性:computed_field 减少“重复存储 + 手动更新”风险,让值随其它字段自动变化。
预备知识
不用手动存 area;根据已有字段动态算 序列化时自动包含 1 2 3 4 5 6 7 8 9 10 11 12 13 from pydantic import BaseModel, Field, computed_fielddef demo_computed_field (): class Rectangle (BaseModel ): width: float = Field(..., gt=0 ) height: float = Field(..., gt=0 ) @computed_field def area (self ) -> float : return self .width * self .height r = Rectangle(width="3.5" , height=2 ) print ("矩形:" , r.model_dump())
小结:已经能做“派生值”。接下来学习“批量自动处理字符串 + 控制额外字段”。
model_config:批量字符串清洗与额外字段策略 让“常见重复清洗操作”一行配置搞定。
预备知识
str_strip_whitespace:所有字符串字段自动 strip str_to_lower:全部转小写(做账号匹配常用) extra=”forbid”:拒绝未声明字段 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from pydantic import BaseModel, ValidationErrordef demo_model_config (): class User (BaseModel ): model_config = { "str_strip_whitespace" : True , "str_to_lower" : True , "extra" : "forbid" , } username: str role: str = "user" u = User(username=" ALICE " ) print ("配置转换:" , u.model_dump()) try : User(username="Bob" , unknown=1 ) except ValidationError as e: print ("额外字段禁止:" , e.errors())
小结:会集中配置模型行为。下一步:把“系统环境变量”转成配置对象。
BaseSettings:环境变量配置加载 帮助你把“全部是字符串”的环境变量自动转换成正确类型。
预备知识
BaseSettings 会读取系统环境变量 env_prefix 设置统一前缀,避免污染 适合应用配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import osfrom pydantic_settings import BaseSettings, SettingsConfigDictdef demo_settings_from_env (): os.environ["APP_HOST" ] = "127.0.0.1" os.environ["APP_PORT" ] = "8000" os.environ["APP_DEBUG" ] = "true" os.environ["APP_DB_URL" ] = "postgres://user:pass@localhost:5432/db" class AppSettings (BaseSettings ): model_config = SettingsConfigDict(env_prefix="APP_" ) host: str port: int debug: bool = False db_url: str timeout: int = 30 s = AppSettings() print ("加载到的配置:" , s.model_dump())
小结:配置来源搞定。下一步:适配“外部字段名”和“内部命名风格”。
alias:外部协议名与内部字段名解耦 应对“外部 JSON 命名风格不同”问题。
预备知识
外部 JSON 可能字段叫 id,内部想叫 user_id alias 映射;by_alias=True 时导出外部名字 populate_by_name 允许用内部名字传值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 from pydantic import BaseModel, Fielddef demo_alias (): class User (BaseModel ): model_config = {"populate_by_name" : True } user_id: int = Field(..., alias="id" ) display_name: str = Field(..., alias="nick" ) u1 = User(id =1 , nick="Tom" ) u2 = User(user_id=2 , display_name="Jerry" ) print ("原字段序列化(内部名字):" , u1.model_dump()) print ("使用别名输出(外部风格):" , u1.model_dump(by_alias=True )) print ("混合输入结果:" , u2.model_dump())
小结:命名桥梁建立。下一步:自定义特殊类型 + 校验。
自定义类型与专用校验 当基础类型语义不够,自己包装一个,提升可读性与复用。
预备知识
自己写一个继承自 str 的类型方便语义表达 arbitrary_types_allowed 允许模型字段用自定义类型 自定义校验逻辑放在 field_validator 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 from pydantic import BaseModel, Field, ValidationError, field_validatordef demo_custom_error (): class PhoneStr (str ): pass class Contact (BaseModel ): model_config = {"arbitrary_types_allowed" : True } phone: PhoneStr = Field(..., description="手机号,11位数字" ) @field_validator("phone" ) def check_phone (cls, v ): if not (v.isdigit() and len (v) == 11 ): raise ValueError("手机号必须为11位数字" ) return v c = Contact(phone=PhoneStr("13812345678" )) print ("联系人:" , c.model_dump()) try : Contact(phone=PhoneStr("abc" )) except ValidationError as e: print ("自定义错误:" , e.errors())
小结:语义更清晰。下一步:解析“多形态消息”。
区分联合(多形态数据):discriminator 让多个“形态”共存,并自动识别是哪一种。
预备知识
多种“形态”的消息统一解析 discriminator 字段用来“告诉模型我是哪个形态” TypeAdapter 可单独对复杂类型(如 List[Union…])做校验 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 from pydantic import BaseModel, Field, ValidationErrorfrom typing import Union , Annotated, List , Literal from pydantic import TypeAdapterdef demo_discriminated_union (): class BaseMsg (BaseModel ): type : str class TextMsg (BaseMsg ): type : Literal ["text" ] content: str class ImageMsg (BaseMsg ): type : Literal ["image" ] url: str width: int height: int MsgUnion = Annotated[Union [TextMsg, ImageMsg], Field(discriminator="type" )] adapter = TypeAdapter(List [MsgUnion]) data = [ {"type" : "text" , "content" : "hello" }, {"type" : "image" , "url" : "xxx.png" , "width" : 100 , "height" : 80 }, ] msgs = adapter.validate_python(data) print ("区分联合解析:" , [m.model_dump() for m in msgs]) try : adapter.validate_python([{"type" : "image" , "url" : "x.png" , "width" : 10 }]) except ValidationError as e: print ("联合错误:" , e.errors())
小结:多形态搞定。接下来关注“安全更新对象”。
model_copy:不可变风格更新 避免“原数据被随意改坏”,做“复制 + 局部改”。
预备知识
防止原对象被意外改动 类似“复制 + 局部修改”实现“函数式”风格 1 2 3 4 5 6 7 8 9 10 11 from pydantic import BaseModeldef demo_model_copy (): class Acc (BaseModel ): id : int balance: float a1 = Acc(id =1 , balance=100 ) a2 = a1.model_copy(update={"balance" : 150 }) print ("原对象:" , a1.model_dump()) print ("新对象:" , a2.model_dump())
小结:更新方式更安全。下一步引入“严格类型”防止模糊转换。
严格类型:StrictInt / StrictBool 当你不想“字符串 1”混进来假扮数字时,用严格类型。
预备知识
默认 int 会接受 “1”;StrictInt 不会 严格模式用来防“脏数据偷偷混进来” 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from pydantic import BaseModel, ValidationError, StrictInt, StrictBooldef demo_strict_types (): class StrictModel (BaseModel ): strict_num: StrictInt strict_flag: StrictBool try : StrictModel(strict_num="1" , strict_flag="true" ) except ValidationError as e: print ("严格类型错误:" , e.errors()) ok = StrictModel(strict_num=1 , strict_flag=True ) print ("严格通过:" , ok.model_dump())
小结:输入更干净。下一步学“输出时挑选字段”。
序列化控制:include / exclude / exclude_none 对外输出时,往往不能“全都给”,需要过滤。
预备知识
include:只要谁(白名单) exclude:排除谁(黑名单) exclude_none=True:自动去掉值为 None 的字段(减轻输出噪声) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from pydantic import BaseModelfrom typing import Optional def demo_serialization_control (): class User (BaseModel ): id : int name: str email: Optional [str ] = None token: str u = User(id =1 , name="Alice" , email=None , token="SECRET" ) print ("完整:" , u.model_dump()) print ("排除敏感:" , u.model_dump(exclude={"token" })) print ("仅输出部分:" , u.model_dump(include={"id" , "name" })) print ("exclude_none:" , u.model_dump(exclude_none=True ))
小结:输出面可控。下一步:提前“丢掉多余垃圾字段”。
外部来源常附带你不关心的字段,直接忽略更省心。
预备知识
外部来源(表单/爬虫)经常混入多余字段 extra=”ignore”:自动丢弃未声明字段,不报错 1 2 3 4 5 6 7 8 9 10 11 12 13 from pydantic import BaseModeldef demo_pre_filter_data (): raw = {"id" : "10" , "name" : "Bob" , "age" : 20 , "unknown" : 1 } class CleanUser (BaseModel ): model_config = {"extra" : "ignore" } id : int name: str age: int user = CleanUser(**raw) print ("外部数据过滤:" , user.model_dump())
小结:输入更“干净”后,错误信息也更“聚焦”。最后来规范错误输出格式。
统一错误输出格式 适合统一给前端 / 日志:可读 + 可机器处理。
预备知识
e.errors() 列表可统一 reshape 成前端友好格式 loc 拼成字符串方便展示路径 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from pydantic import BaseModel, Field, ValidationErrordef demo_error_handling_pattern (): class Simple (BaseModel ): a: int b: int = Field(..., gt=0 ) try : Simple(a="x" , b=0 ) except ValidationError as e: errors = [ { "loc" : "." .join(str (p) for p in err["loc" ]), "msg" : err["msg" ], "type" : err["type" ], } for err in e.errors() ] print ("统一错误格式:" , errors)
小结:到这里,你已经掌握从“声明 → 校验 → 嵌套 → 多形态 → 清洗 → 配置 → 严格输出 → 错误格式化”的完整链路。
学习路径建议 先懂 BaseModel / Field / ValidationError(最核心三件套)。 再加 field_validator / model_validator 做细与“跨字段”逻辑。 逐步引入 Settings / discriminator / 严格类型提升质量。 熟练后用 include/exclude + 错误格式统一进行工程打磨。 动态模型 在某些情况下,直到运行时才知道模型的结构。为此 pydantic 提供了 create_model 允许动态创建模型的方法。
1 2 3 from pydantic import BaseModel, create_model DynamicFoobarModel = create_model('DynamicFoobarModel', foo=(str, ...), bar=123)
ValidationError看错误结构 validator 验证器 field_validator/model validator
验证器是“类方法”,因此它们接收的第一个参数值是 UserModel 类,而不是 UserModel
第二个参数始终是要验证的字段值,可以随意命名
单个验证器可以通过传递多个字段名称来应用于多个字段,也可以通过传递特殊值在所有字段上调用单个验证器 '*'
关键字参数 pre 将导致在其他验证之前调用验证器
通过 each_item=True 将导致验证器被施加到单独的值(例如 List,Dict,Set 等),而不是整个对象
关键字参数 always 将导致始终验证,出于性能原因,默认情况下,当未提供值时,不会为字段调用验证器。然而,在某些情况下,始终调用验证器可能很有用或需要,例如设置动态默认值。
allow_reuse 可以在多个字段/模型上使用相同的验证器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 from pydantic import BaseModel, ValidationError, validatorclass UserModel (BaseModel ): name: str username: str password1: str password2: str @validator('name' ) def name_must_contain_space (cls, v ): if ' ' not in v: raise ValueError('must contain a space' ) return v.title() @validator('password2' ) def passwords_match (cls, v, values, **kwargs ): if 'password1' in values and v != values['password1' ]: raise ValueError('passwords do not match' ) return v @validator('username' ) def username_alphanumeric (cls, v ): assert v.isalnum(), 'must be alphanumeric' return v user = UserModel( name='samuel colvin' , username='scolvin' , password1='zxcvbn' , password2='zxcvbn' , ) print (user)try : UserModel( name='samuel' , username='scolvin' , password1='zxcvbn' , password2='zxcvbn2' , ) except ValidationError as e: print (e) """ 2 validation errors for UserModel name must contain a space (type=value_error) password2 passwords do not match (type=value_error) """
Settings、alias、discriminator:工程化 严格类型:include/exclude:质量与输出控制 类型 标准库类型 bool int:int(value) float: float(value),强制转换为 float str:字符串按原样接受,int、float 和 Decimal 使用 str(v) 强制转换,bytes 和 bytearray 使用 v.decode() 转换,继承自 str 的枚举使用 v.value 转换,所有其他类型都会导致错误。 bytes: 字节是按原格式接受的,bytearray 使用 bytes(v) 进行转换,str 使用 v.encode() 进行转换,int、float 和 Decimal 使用 str(v).encode() 进行转换。 typing的类型 datetime.date:有关解析和验证的更多细节 datetime.time:有关解析和验证的更多细节 datetime.datetime:有关解析和验证的更多细节 datetime.timedelta:有关解析和验证的更多细节 ipaddress.IPv4Address:通过将值传递给 IPv4Address(v),简单地使用类型本身进行验证;有关其他自定义 IP 地址类型 ipaddress.IPv4Interface:通过将值传递给 IPv4Interface(v),简单地使用类型本身进行验证;有关其他自定义 IP 地址类型 ipaddress.IPv4Network:通过将值传递给 IPv4Network(v),简单地使用类型本身进行验证;有关其他自定义 IP 地址类型 ipaddress.IPv6Address:通过将值传递给 IPv6Address(v),简单地使用类型本身进行验证;有关其他自定义 IP 地址类型 ipaddress.IPv6Interface:通过将值传递给 IPv6Interface(v),简单地使用类型本身进行验证;有关其他自定义 IP 地址类型 ipaddress.IPv6.Network:通过将值传递给 IPv6Network(v),简单地使用类型本身进行验证;有关其他自定义 IP 地址类型 enum.Enum:检查值是有效的 Enum 实例。 subclass of enum.Enum:检查值是有效的枚举成员。更多细节, enum.IntEnum:检查值是有效的 IntEnum 实例。 subclass of enum.IntEnum:检查值是有效的整数枚举成员。更多细节, decimal.Decimal:ydantic 会尝试将值转换为字符串,然后将那个字符串传递个 Decimal(v)。:athlib.Path:通过将值传递给 Path(v) ,简单地使用类型本身进行验证。对于其他更严格的路径类型, uuid.UUID:字符串和字节 (转换为字符串) 被传递到 UUID(v),对于 bytes 和 bytearray ,回退到 UUID(bytes=v);有关其他更严格的 UUID 类型 ByteSize: 将带有单位的字节字符串转换为字节。 typing 中的可迭代类型 Sequence:生成器 Union[int, str]:联合类型,允许接受不同的类型Optional[int]:可选类型,相当于 Union[int, None]Pydantic 类型 FilePath:与 Path 类似,但路径必须存在且必须是文件 DirectoryPath:与 Path 类似,但路径必须存大且时目录 EmailStr:依赖于 email-validator:输入字符串必须是有效的 email 地址,输出简单字符串 NameEmail:依赖于 email-validator,输入字符串必须是有效的 email 地址或是 Fred Bloggs <fred.bloggs@example.com> 这样的格式,输出是一个 NameEmail 对象,该对象有两个属性:name 和 email PyObject: 需要一个可调用对象或一个包含 . 的表示导入路径的字符串。如果提供的是一个字符串,则从该字符串所表示的导入路径加载最后一个 . 右边的子串所表示的可导入 Python 对象。 例如,如果提供了 ‘math.cos’,则结果字段值将为函数 cos。如果提供了 pydantic.dataclasses.dataclass,则结果字段值将为 dataclass。 Color: 用于解析 HTML 和 CSS 颜色。 Json: 一个特殊的类型包装器,在解析之前加载 JSON; PaymentCardNumber: 对支付卡进行解析和验证; AnyUrl: 任意 URL。 AnyHttpUrl: 一个 HTTP URL。 HttpUrl: 更严格的 HTTP URL。 PostgresDsn: ostgres DSN 样式的 URL。 UUID1: 需要类型 1 的有效 UUID。 UUID3: 需要类型 3 的有效 UUID。 UUID4: 需要类型 4 的有效 UUID。 UUID5: 需要类型 5 的有效 UUID。 SecretBytes: 值部分 (partially) 保密的字节。 SecretStr: 值部分 (partially) 保密的字符串。 IPvAnyAddress: 允许一个 IPv4Address 或一个 IPv6Address。 IPvAnyInterface: 允许一个 IPv4Interface 或一个 IPv6Interface。 IPvAnyNetwork: 允许一个 IPv4Network 或一个 IPv6Network。 NegativeFloat: 允许负的浮点数; 使用标准的 float 解析,然后检查该值是否小于 0; NegativeInt: 允许负的整数; 使用标准的 int 解析,然后检查该值是否小于 0; PositiveFloat: 允许正的浮点数; 使用标准的 float 解析,然后检查该值是否大于 0; PosiviteInt: 允许正的整数; 使用标准的 int 解析,然后检查该值是否大于 0; conbytes: 用于约束 bytes 的类型方法。 condecimal: 用于约束 Decimal 的类型方法。 confloat: 用于约束 float 的类型方法。 conint: 用于约束 int 的类型方法。 conlist: 用于约束 list 的类型方法。 conset: 用于约束 set 的类型方法。 constr: 用于约束 str 的类型方法。 typing typing:【标准库】类型标注支持
作用:类型检查,防止运行时出现参数和返回值类型不符合 作为开发文档附加说明,方便使用者调用时传入和返回参数类型 模块加入后并不会影响程序的运行,不会报正式的错误,只有提醒 IDE 代码提示 使用场景 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 def _add (a: int , b: int ) -> int : return a + b name: str = "Li" age: int = 18 items: list [int ] = [1 , 2 , 3 ] from typing import TypeAlias, List vector = List [float ] Vector: TypeAlias = List [float ]
类型 int, float, bool, str, bytesPython 3.9+:标准类型直接用list:允许 list,tuple,set,frozenset,deque, 或生成器并转换为列表tuple:允许 list,tuple,set,frozenset,deque, 或生成器并转换为元组dict:字典类型set:允许 list,tuple,set,frozenset,deque, 或生成器和转换为集合;frozenset:允许 list,tuple,set,frozenset,deque, 或生成器和强制转换为冻结集deque:允许 list,tuple,set,frozenset,deque, 或生成器和强制转换为双端队列 Python 3.8Any:允许任何类型,包括 None,因此一个 Any 字段是可选的。TypeVar:根据 constraints 或 bound 约束允许的值。Union[int,str]:可接受多种类型的任意一种比如:list[Union[int, str]] = [3, 5, "test", "fun"] Optional:可以是给定类型的值或者是None。对于可能为空的返回值或参数非常有用Optional[x] 是 Union[x, None] 的快捷方式List[int]:Tuple[int,str,float]=(3, "yes", 7.5):Tuple[int, ...] = (1, 2, 3)typing.DictDict[str, float] = {"field": 2.0}SetFrozenSet:Deque:Sequence:Iterable:这是为不应该被消耗的可迭代对象保留的。Listeral:限定变量只能取某些特定的字面量,常用于配置选项、枚举值 TypeAlias:为复杂类型创建别名 Type:Callable:可调用对象(比如函数、方法或类)可带输出: Callable[[int], str] Pattern:将会导致输入值被传递到 re.compile(v) 以创建一个正则表达式模式。 None, type(None) 或 Literal[None]:只允许 None 值TypeVar:泛型类:类或方法时指定某些参数或返回值的类型可以是任意类型,但是调用者必须提供一个具体的类型来替代这个类型变量。TypeVar 主要用于定义泛型函数、类和容器。 1 2 3 4 5 6 7 from typing import TypeVar, List T = TypeVar('T' ) def first_element (lst: List [T] ) -> T: """Return the first element of a non-empty list.""" return lst[0 ] if lst else None
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from typing import NewTypeUserId = NewType('UserId' , int ) def get_user_name (user_id: UserId ) -> str : return f"User {user_id} " user_id = UserId(42 ) print (get_user_name(user_id))
object:对象datetime 的 date,datetime,time,timedelta 等日期类型 FilePath,文件路径 DirectoryPath 目录路径 EmailStr 电子邮件地址 NameEmail 有效的电子邮件地址或格式 PyObject 需要一个字符串并加载可在该虚线路径中导入的 python 对象; Color 颜色类型 AnyUrl 任意网址 SecretStr、SecretBytes 敏感信息,将被格式化为 '**********' 或 '' Json 类型 PaymentCardNumber 支付卡类型 Enum 约束类型,可以使用 con* 类型函数限制许多常见类型的值 list[str]:字符串数组 tuple[int,int]:2 个整数元素的元组 tuple[int,…]:任意数量整数元素的元组 dict[str,int]:key 为字符串,value 是整数的字典 Iterable[int]:可迭代类型,元素为整数 Sequence[bool]:布尔值序列 Mapping[str,int]:key 是字符串,value 是整数的映射 Class:使用自 定上课铃类做为类型注释 Callable:是否可调用 NamedTuple TypeVar:任意类型 Generator:生成器类型 NewType:声明一个不同的类型而又不实际执行创建新类型,在运行时,将返回一个仅返回其参数的虚拟函数 overload:给同一个函数多个类型来更准确地描述函数的行为 Literal:表明一个表达式等于某个特定的原始值。例如,如果我们用 type 注释一个变量 Literal["foo"],mypy 将理解该变量不仅是 typestr,而且还特别等于 string"foo"。 Final:限定符来指示不应重新分配、重新定义或覆盖名称或属性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 from typing improt Literal , Union , Optional def func_test (name:str ,age:int )-> str : print (type (name)) print (f'My name is {name} ,age is {age} ' ) print (func_test.__annotations__)typing.get_type_hints() 内置类型 x: int = 1 x: float = 1.0 x: bool = True x: str = "test" x: bytes = b"test" child: bool if age < 18 : child = True else : child = False def stringify (num: int ) -> str : return str (num) def f (n: int ) -> Iterable[int ]: i = 0 while i < n: yield i i += 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from typing import List ,Set ,Tuple from typing import Optional def get_student_info (info:List [str ,int ,float ],teacher: Dict [str , float ] ): name=info[0 ] age=info[1 ] height=info[2 ] def say_hi (name: Optional [str ] = None ): if name is not None : print (f"Hey {name} !" ) else : print ("Hello World" )
TYPE_CHECKING 1 2 3 4 5 from typing import TYPE_CHECKINGif TYPE_CHECKING: from ..manager import PageManager