python庫pydantic的入門簡易教程
一、簡介
pydantic 庫是 python 中用于數據接口定義檢查與設置管理的庫。
pydantic 在運行時強制執(zhí)行類型提示,并在數據無效時提供友好的錯誤。
它具有如下優(yōu)點:
1.與 IDE/linter 完美搭配,不需要學習新的模式,只是使用類型注解定義類的實例
2.多用途,BaseSettings 既可以驗證請求數據,也可以從環(huán)境變量中讀取系統(tǒng)設置快速
3.可以驗證復雜結構
4.可擴展,可以使用validator裝飾器裝飾的模型上的方法來擴展驗證
5.數據類集成,除了BaseModel,pydantic還提供了一個dataclass裝飾器,它創(chuàng)建帶有輸入數據解析和驗證的普通 Python 數據類。
二、安裝
pip install pydantic
要測試 pydantic 是否已編譯,請運行:
import pydantic print('compiled:', pydantic.compiled)
支持使用dotenv文件獲取配置,需要安裝 python-dotenv
pip install pydantic[dotenv]
三、常見模型
pydantic中定義對象都是通過模型的,你可以認為模型就是類型語言中的類型。
1、BaseModel 基本模型
from pydantic import BaseModel class User(BaseModel): ? ? id: int ? ? name = 'Jane Doe
上面的例子,定義了一個User模型,繼承自BaseModel,有2個字段,id是一個整數并且是必需的,name是一個帶有默認值的字符串并且不是必需的
實例化使用:
user = User(id='123')
例化將執(zhí)行所有解析和驗證,如果有錯誤則會觸發(fā) ValidationError 報錯。
模型具有以下屬性:
- dict() 模型字段和值的字典
- json() JSON 字符串表示dict()
- copy() 模型的副本(默認為淺表副本)
- parse_obj() 使用dict解析數據
- parse_raw 將str或bytes并將其解析為json,然后將結果傳遞給parse_obj
- parse_file 文件路徑,讀取文件并將內容傳遞給parse_raw。如果content_type省略,則從文件的擴展名推斷
- from_orm() 從ORM 對象創(chuàng)建模型
- schema() 返回模式的字典
- schema_json() 返回該字典的 JSON 字符串表示
- construct() 允許在沒有驗證的情況下創(chuàng)建模型
- fields_set 初始化模型實例時設置的字段名稱集
- fields 模型字段的字典
- config 模型的配置類
2、遞歸模型
可以使用模型本身作為注釋中的類型來定義更復雜的數據結構。
from typing import List from pydantic import BaseModel class Foo(BaseModel): ? ? count: int ? ? size: float = None class Bar(BaseModel): ? ? apple = 'x' ? ? banana = 'y' class Spam(BaseModel): ? ? foo: Foo ? ? bars: List[Bar]
3、GenericModel 通用模型(泛型):
使用 typing.TypeVar 的實例作為參數,傳遞給 typing.Generic,然后在繼承了pydantic.generics.GenericModel 的模型中使用:
from typing import Generic, TypeVar, Optional, List from pydantic import BaseModel, validator, ValidationError from pydantic.generics import GenericModel DataT = TypeVar('DataT') class Error(BaseModel): ? ? code: int ? ? message: str class DataModel(BaseModel): ? ? numbers: List[int] ? ? people: List[str] class Response(GenericModel, Generic[DataT]): ? ? data: Optional[DataT] ? ? error: Optional[Error] ? ? @validator('error', always=True) ? ? def check_consistency(cls, v, values): ? ? ? ? if v is not None and values['data'] is not None: ? ? ? ? ? ? raise ValueError('must not provide both data and error') ? ? ? ? if v is None and values.get('data') is None: ? ? ? ? ? ? raise ValueError('must provide data or error') ? ? ? ? return v data = DataModel(numbers=[1, 2, 3], people=[]) error = Error(code=404, message='Not found') print(Response[int](data=1)) #> data=1 error=None print(Response[str](data='value')) #> data='value' error=None print(Response[str](data='value').dict()) #> {'data': 'value', 'error': None} print(Response[DataModel](data=data).dict()) """ { ? ? 'data': {'numbers': [1, 2, 3], 'people': []}, ? ? 'error': None, } """ print(Response[DataModel](error=error).dict()) """ { ? ? 'data': None, ? ? 'error': {'code': 404, 'message': 'Not found'}, } """ try: ? ? Response[int](data='value') except ValidationError as e: ? ? print(e) ? ? """ ? ? 2 validation errors for Response[int] ? ? data ? ? ? value is not a valid integer (type=type_error.integer) ? ? error ? ? ? must provide data or error (type=value_error) ? ? """
4、create_model 動態(tài)模型
在某些情況下,直到運行時才知道模型的結構。為此 pydantic 提供了create_model允許動態(tài)創(chuàng)建模型的方法。
from pydantic import BaseModel, create_model DynamicFoobarModel = create_model('DynamicFoobarModel', foo=(str, ...), bar=123)
四、常用類型
- None,type(None)或Literal[None]只允許None值
- bool 布爾類型
- int 整數類型
- float 浮點數類型
- str 字符串類型
- bytes 字節(jié)類型
- 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, 或生成器和強制轉換為雙端隊列
- datetime 的date,datetime,time,timedelta 等日期類型
- typing 中的 Deque, Dict, FrozenSet, List, Optional, Sequence, Set, Tuple, Union,Callable,Pattern等類型
- FilePath,文件路徑
- DirectoryPath 目錄路徑
- EmailStr 電子郵件地址
- NameEmail 有效的電子郵件地址或格式
- PyObject 需要一個字符串并加載可在該虛線路徑中導入的 python 對象;
- Color 顏色類型
- AnyUrl 任意網址
SecretStr、SecretBytes 敏感信息,將被格式化為’**********‘或’’
- Json 類型
- PaymentCardNumber 支付卡類型
- 約束類型,可以使用con*類型函數限制許多常見類型的值
conlist
1.item_type: Type[T]: 列表項的類型
2.min_items: int = None: 列表中的最小項目數
3.max_items: int = None: 列表中的最大項目數
conset
1.item_type: Type[T]: 設置項目的類型
2.min_items: int = None: 集合中的最小項目數
3.max_items: int = None: 集合中的最大項目數
conint
1.strict: bool = False: 控制類型強制
2.gt: int = None: 強制整數大于設定值
3.ge: int = None: 強制整數大于或等于設定值
4.lt: int = None: 強制整數小于設定值
5.le: int = None: 強制整數小于或等于設定值
6.multiple_of: int = None: 強制整數為設定值的倍數
confloat
1.strict: bool = False: 控制類型強制
2.gt: float = None: 強制浮點數大于設定值
3.ge: float = None: 強制 float 大于或等于設定值
4.lt: float = None: 強制浮點數小于設定值
5.le: float = None: 強制 float 小于或等于設定值
6.multiple_of: float = None: 強制 float 為設定值的倍數
condecimal
1.gt: Decimal = None: 強制十進制大于設定值
2.ge: Decimal = None: 強制十進制大于或等于設定值
3.lt: Decimal = None: 強制十進制小于設定值
4.le: Decimal = None: 強制十進制小于或等于設定值
5.max_digits: int = None: 小數點內的最大位數。它不包括小數點前的零或尾隨的十進制零
6.decimal_places: int = None: 允許的最大小數位數。它不包括尾隨十進制零
7.multiple_of: Decimal = None: 強制十進制為設定值的倍數
constr
1.strip_whitespace: bool = False: 刪除前尾空格
2.to_lower: bool = False: 將所有字符轉為小寫
3.strict: bool = False: 控制類型強制
4.min_length: int = None: 字符串的最小長度
5.max_length: int = None: 字符串的最大長度
6.curtail_length: int = None: 當字符串長度超過設定值時,將字符串長度縮小到設定值
7.regex: str = None: 正則表達式來驗證字符串
conbytes
1.strip_whitespace: bool = False: 刪除前尾空格
2.to_lower: bool = False: 將所有字符轉為小寫
3.min_length: int = None: 字節(jié)串的最小長度
4.max_length: int = None: 字節(jié)串的最大長度
嚴格類型,您可以使用StrictStr,StrictBytes,StrictInt,StrictFloat,和StrictBool類型,以防止強制兼容類型
五、驗證器
使用validator裝飾器可以實現自定義驗證和對象之間的復雜關系。
from pydantic import BaseModel, ValidationError, validator class 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) #> name='Samuel Colvin' username='scolvin' password1='zxcvbn' password2='zxcvbn' 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) ? ? """
關于驗證器的一些注意事項:
- 驗證器是“類方法”,因此它們接收的第一個參數值是UserModel類,而不是UserModel
- 第二個參數始終是要驗證的字段值,可以隨意命名
- 單個驗證器可以通過傳遞多個字段名稱來應用于多個字段,也可以通過傳遞特殊值在所有字段上調用單個驗證器’*’
- 關鍵字參數pre將導致在其他驗證之前調用驗證器
- 通過each_item=True將導致驗證器被施加到單獨的值(例如List,Dict,Set等),而不是整個對象
from typing import List from pydantic import BaseModel, ValidationError, validator class ParentModel(BaseModel): ? ? names: List[str] class ChildModel(ParentModel): ? ? @validator('names', each_item=True) ? ? def check_names_not_empty(cls, v): ? ? ? ? assert v != '', 'Empty strings are not allowed.' ? ? ? ? return v # This will NOT raise a ValidationError because the validator was not called try: ? ? child = ChildModel(names=['Alice', 'Bob', 'Eve', '']) except ValidationError as e: ? ? print(e) else: ? ? print('No ValidationError caught.') ? ? #> No ValidationError caught. class ChildModel2(ParentModel): ? ? @validator('names') ? ? def check_names_not_empty(cls, v): ? ? ? ? for name in v: ? ? ? ? ? ? assert name != '', 'Empty strings are not allowed.' ? ? ? ? return v try: ? ? child = ChildModel2(names=['Alice', 'Bob', 'Eve', '']) except ValidationError as e: ? ? print(e) ? ? """ ? ? 1 validation error for ChildModel2 ? ? names ? ? ? Empty strings are not allowed. (type=assertion_error) ? ? """
- 關鍵字參數 always 將導致始終驗證,出于性能原因,默認情況下,當未提供值時,不會為字段調用驗證器。然而,在某些情況下,始終調用驗證器可能很有用或需要,例如設置動態(tài)默認值。
- allow_reuse 可以在多個字段/模型上使用相同的驗證器
from pydantic import BaseModel, validator def normalize(name: str) -> str: ? ? return ' '.join((word.capitalize()) for word in name.split(' ')) class Producer(BaseModel): ? ? name: str ? ? # validators ? ? _normalize_name = validator('name', allow_reuse=True)(normalize) class Consumer(BaseModel): ? ? name: str ? ? # validators ? ? _normalize_name = validator('name', allow_reuse=True)(normalize)
六、配置
如果您創(chuàng)建一個繼承自BaseSettings的模型,模型初始化程序將嘗試通過從環(huán)境中讀取,來確定未作為關鍵字參數傳遞的任何字段的值。(如果未設置匹配的環(huán)境變量,則仍將使用默認值。)
這使得很容易:
- 創(chuàng)建明確定義、類型提示的應用程序配置類
- 自動從環(huán)境變量中讀取對配置的修改
- 在需要的地方手動覆蓋初始化程序中的特定設置(例如在單元測試中)
from typing import Set from pydantic import ( ? ? BaseModel, ? ? BaseSettings, ? ? PyObject, ? ? RedisDsn, ? ? PostgresDsn, ? ? Field, ) class SubModel(BaseModel): ? ? foo = 'bar' ? ? apple = 1 class Settings(BaseSettings): ? ? auth_key: str ? ? api_key: str = Field(..., env='my_api_key') ? ? redis_dsn: RedisDsn = 'redis://user:pass@localhost:6379/1' ? ? pg_dsn: PostgresDsn = 'postgres://user:pass@localhost:5432/foobar' ? ? special_function: PyObject = 'math.cos' ? ? # to override domains: ? ? # export my_prefix_domains='["foo.com", "bar.com"]' ? ? domains: Set[str] = set() ? ? # to override more_settings: ? ? # export my_prefix_more_settings='{"foo": "x", "apple": 1}' ? ? more_settings: SubModel = SubModel() ? ? class Config: ? ? ? ? env_prefix = 'my_prefix_' ?# defaults to no prefix, i.e. "" ? ? ? ? fields = { ? ? ? ? ? ? 'auth_key': { ? ? ? ? ? ? ? ? 'env': 'my_auth_key', ? ? ? ? ? ? }, ? ? ? ? ? ? 'redis_dsn': { ? ? ? ? ? ? ? ? 'env': ['service_redis_dsn', 'redis_url'] ? ? ? ? ? ? } ? ? ? ? } print(Settings().dict()) """ { ? ? 'auth_key': 'xxx', ? ? 'api_key': 'xxx', ? ? 'redis_dsn': RedisDsn('redis://user:pass@localhost:6379/1', scheme='redis', user='user', password='pass', host='localhost', host_type='int_domain', port='6379', path='/1'), ? ? 'pg_dsn': PostgresDsn('postgres://user:pass@localhost:5432/foobar', scheme='postgres', user='user', password='pass', host='localhost', host_type='int_domain', port='5432', path='/foobar'), ? ? 'special_function': <built-in function cos>, ? ? 'domains': set(), ? ? 'more_settings': {'foo': 'bar', 'apple': 1}, } """
支持 Dotenv 文件設置變量,pydantic 有兩種方式加載它:
class Settings(BaseSettings): ? ? ... ? ? class Config: ? ? ? ? env_file = '.env' ? ? ? ? env_file_encoding = 'utf-8'
或者
settings=Settings(_env_file='prod.env',_env_file_encoding='utf-8')
即使使用 dotenv 文件,pydantic 仍會讀取環(huán)境變量,環(huán)境變量將始終優(yōu)先于從 dotenv 文件加載的值。
pydantic 支持設置敏感信息文件,同樣有2種方式加載:
class Settings(BaseSettings): ? ? ... ? ? database_password: str ? ? class Config: ? ? ? ? secrets_dir = '/var/run'
或者
settings = Settings(_secrets_dir='/var/run')
即使使用 secrets 目錄,pydantic仍會從 dotenv 文件或環(huán)境中讀取環(huán)境變量,dotenv 文件和環(huán)境變量將始終優(yōu)先于從 secrets 目錄加載的值。
七、與 mypy 一起使用
Pydantic 附帶了一個 mypy 插件,向 mypy 添加了許多重要的特定于 pydantic 的功能,以提高其對代碼進行類型檢查的能力。
例如以下腳本:
from datetime import datetime from typing import List, Optional from pydantic import BaseModel, NoneStr class Model(BaseModel): ? ? age: int ? ? first_name = 'John' ? ? last_name: NoneStr = None ? ? signup_ts: Optional[datetime] = None ? ? list_of_ints: List[int] m = Model(age=42, list_of_ints=[1, '2', b'3']) print(m.middle_name) ?# not a model field! Model() ?# will raise a validation error for age and list_of_ints
在沒有任何特殊配置的情況下,mypy 會捕獲其中一個錯誤:
13: error: "Model" has no attribute "middle_name"
啟用插件后,它會同時捕獲:
13: error: "Model" has no attribute "middle_name"
16: error: Missing named argument "age" for "Model"
16: error: Missing named argument "list_of_ints" for "Model"
要啟用該插件,只需添加pydantic.mypy到mypy 配置文件中的插件列表:
[mypy] plugins = pydantic.mypy
要更改插件設置的值,請??在 mypy 配置文件中創(chuàng)建一個名為 的部分[pydantic-mypy],并為要覆蓋的設置添加鍵值對:
[mypy] plugins = pydantic.mypy follow_imports = silent warn_redundant_casts = True warn_unused_ignores = True disallow_any_generics = True check_untyped_defs = True no_implicit_reexport = True # for strict mypy: (this is the tricky one :-)) disallow_untyped_defs = True [pydantic-mypy] init_forbid_extra = True init_typed = True warn_required_dynamic_aliases = True warn_untyped_fields = True
到此這篇關于python庫pydantic的入門簡易教程的文章就介紹到這了,更多相關python pydantic內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
python中shapefile庫讀取shapefile文件信息
本文主要介紹了python中shapefile庫讀取shapefile文件信息,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-06-06如何使用python的ctypes調用醫(yī)保中心的dll動態(tài)庫下載醫(yī)保中心的賬單
這篇文章主要介紹了如何使用python的ctypes調用醫(yī)保中心的dll動態(tài)庫下載醫(yī)保中心的賬單,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-05-05如何使用python的plot繪制loss、acc曲線并存儲成圖片
在數據可視化中曲線圖是一種常見的展示數據趨勢的方式,Python作為一種強大的編程語言,提供了豐富的數據處理和可視化庫,使得繪制曲線圖變得非常簡單,下面這篇文章主要給大家介紹了關于如何使用python的plot繪制loss、acc曲線并存儲成圖片的相關資料,需要的朋友可以參考下2024-03-03