溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

python庫pydantic怎么用

發(fā)布時(shí)間:2022-03-29 09:08:28 來源:億速云 閱讀:169 作者:小新 欄目:開發(fā)技術(shù)

這篇文章主要介紹了python庫pydantic怎么用,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

    一、簡(jiǎn)介

    pydantic 庫是 python 中用于數(shù)據(jù)接口定義檢查與設(shè)置管理的庫。

    pydantic 在運(yùn)行時(shí)強(qiáng)制執(zhí)行類型提示,并在數(shù)據(jù)無效時(shí)提供友好的錯(cuò)誤。

    它具有如下優(yōu)點(diǎn):

    • 與 IDE/linter 完美搭配,不需要學(xué)習(xí)新的模式,只是使用類型注解定義類的實(shí)例

    • 多用途,BaseSettings 既可以驗(yàn)證請(qǐng)求數(shù)據(jù),也可以從環(huán)境變量中讀取系統(tǒng)設(shè)置

    • 快速

    • 可以驗(yàn)證復(fù)雜結(jié)構(gòu)

    • 可擴(kuò)展,可以使用validator裝飾器裝飾的模型上的方法來擴(kuò)展驗(yàn)證

    • 數(shù)據(jù)類集成,除了BaseModel,pydantic還提供了一個(gè)dataclass裝飾器,它創(chuàng)建帶有輸入數(shù)據(jù)解析和驗(yàn)證的普通 Python 數(shù)據(jù)類。

    二、安裝

    pip install pydantic

    要測(cè)試 pydantic 是否已編譯,請(qǐng)運(yùn)行:

    import pydantic
    print('compiled:', pydantic.compiled)

    支持使用dotenv文件獲取配置,需要安裝 python-dotenv

    pip install pydantic[dotenv]

    三、常見模型

    pydantic中定義對(duì)象都是通過模型的,你可以認(rèn)為模型就是類型語言中的類型。

    1、BaseModel 基本模型

    from pydantic import BaseModel
    class User(BaseModel):
        id: int
        name = 'Jane Doe'

    上面的例子,定義了一個(gè)User模型,繼承自BaseModel,有2個(gè)字段,id是一個(gè)整數(shù)并且是必需的,name是一個(gè)帶有默認(rèn)值的字符串并且不是必需的

    實(shí)例化使用:

    user = User(id='123')

    實(shí)例化將執(zhí)行所有解析和驗(yàn)證,如果有錯(cuò)誤則會(huì)觸發(fā) ValidationError 報(bào)錯(cuò)。

    模型具有以下屬性:

    • dict() 模型字段和值的字典

    • json() JSON 字符串表示dict()

    • copy() 模型的副本(默認(rèn)為淺表副本)

    • parse_obj() 使用dict解析數(shù)據(jù)

    • parse_raw 將str或bytes并將其解析為json,然后將結(jié)果傳遞給parse_obj

    • parse_file 文件路徑,讀取文件并將內(nèi)容傳遞給parse_raw。如果content_type省略,則從文件的擴(kuò)展名推斷

    • from_orm() 從ORM 對(duì)象創(chuàng)建模型

    • schema() 返回模式的字典

    • schema_json() 返回該字典的 JSON 字符串表示

    • construct() 允許在沒有驗(yàn)證的情況下創(chuàng)建模型

    • __fields_set__ 初始化模型實(shí)例時(shí)設(shè)置的字段名稱集

    • __fields__ 模型字段的字典

    • __config__ 模型的配置類

    2、遞歸模型

    可以使用模型本身作為注釋中的類型來定義更復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。

    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 的實(shí)例作為參數(shù),傳遞給 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 動(dòng)態(tài)模型

    在某些情況下,直到運(yùn)行時(shí)才知道模型的結(jié)構(gòu)。為此 pydantic 提供了create_model允許動(dòng)態(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 整數(shù)類型

    • float 浮點(diǎn)數(shù)類型

    • str 字符串類型

    • bytes 字節(jié)類型

    • list 允許list,tuple,set,frozenset,deque, 或生成器并轉(zhuǎn)換為列表

    • tuple 允許list,tuple,set,frozenset,deque, 或生成器并轉(zhuǎn)換為元組

    • dict 字典類型

    • set 允許list,tuple,set,frozenset,deque, 或生成器和轉(zhuǎn)換為集合;

    • frozenset 允許list,tuple,set,frozenset,deque, 或生成器和強(qiáng)制轉(zhuǎn)換為凍結(jié)集

    • deque 允許list,tuple,set,frozenset,deque, 或生成器和強(qiáng)制轉(zhuǎn)換為雙端隊(duì)列

    • datetime 的date,datetime,time,timedelta 等日期類型

    • typing 中的 Deque, Dict, FrozenSet, List, Optional, Sequence, Set, Tuple, Union,Callable,Pattern等類型

    • FilePath,文件路徑

    • DirectoryPath 目錄路徑

    • EmailStr 電子郵件地址

    • NameEmail 有效的電子郵件地址或格式

    • PyObject 需要一個(gè)字符串并加載可在該虛線路徑中導(dǎo)入的 python 對(duì)象;

    • Color 顏色類型

    • AnyUrl 任意網(wǎng)址

    • SecretStr、SecretBytes 敏感信息,將被格式化為'**********'或''

    • Json 類型

    • PaymentCardNumber 支付卡類型

    • 約束類型,可以使用con*類型函數(shù)限制許多常見類型的值

      • conlist

    • item_type: Type[T]: 列表項(xiàng)的類型

    • min_items: int = None: 列表中的最小項(xiàng)目數(shù)

    • max_items: int = None: 列表中的最大項(xiàng)目數(shù)

    • conset

    • item_type: Type[T]: 設(shè)置項(xiàng)目的類型

    • min_items: int = None: 集合中的最小項(xiàng)目數(shù)

    • max_items: int = None: 集合中的最大項(xiàng)目數(shù)

    • conint

    • strict: bool = False: 控制類型強(qiáng)制

    • gt: int = None: 強(qiáng)制整數(shù)大于設(shè)定值

    • ge: int = None: 強(qiáng)制整數(shù)大于或等于設(shè)定值

    • lt: int = None: 強(qiáng)制整數(shù)小于設(shè)定值

    • le: int = None: 強(qiáng)制整數(shù)小于或等于設(shè)定值

    • multiple_of: int = None: 強(qiáng)制整數(shù)為設(shè)定值的倍數(shù)

    • confloat

    • strict: bool = False: 控制類型強(qiáng)制

    • gt: float = None: 強(qiáng)制浮點(diǎn)數(shù)大于設(shè)定值

    • ge: float = None: 強(qiáng)制 float 大于或等于設(shè)定值

    • lt: float = None: 強(qiáng)制浮點(diǎn)數(shù)小于設(shè)定值

    • le: float = None: 強(qiáng)制 float 小于或等于設(shè)定值

    • multiple_of: float = None: 強(qiáng)制 float 為設(shè)定值的倍數(shù)

    • condecimal

    • gt: Decimal = None: 強(qiáng)制十進(jìn)制大于設(shè)定值

    • ge: Decimal = None: 強(qiáng)制十進(jìn)制大于或等于設(shè)定值

    • lt: Decimal = None: 強(qiáng)制十進(jìn)制小于設(shè)定值

    • le: Decimal = None: 強(qiáng)制十進(jìn)制小于或等于設(shè)定值

    • max_digits: int = None: 小數(shù)點(diǎn)內(nèi)的最大位數(shù)。它不包括小數(shù)點(diǎn)前的零或尾隨的十進(jìn)制零

    • decimal_places: int = None: 允許的最大小數(shù)位數(shù)。它不包括尾隨十進(jìn)制零

    • multiple_of: Decimal = None: 強(qiáng)制十進(jìn)制為設(shè)定值的倍數(shù)

    • constr

    • strip_whitespace: bool = False: 刪除前尾空格

    • to_lower: bool = False: 將所有字符轉(zhuǎn)為小寫

    • strict: bool = False: 控制類型強(qiáng)制

    • min_length: int = None: 字符串的最小長(zhǎng)度

    • max_length: int = None: 字符串的最大長(zhǎng)度

    • curtail_length: int = None: 當(dāng)字符串長(zhǎng)度超過設(shè)定值時(shí),將字符串長(zhǎng)度縮小到設(shè)定值

    • regex: str = None: 正則表達(dá)式來驗(yàn)證字符串

    • conbytes

    • strip_whitespace: bool = False: 刪除前尾空格

    • to_lower: bool = False: 將所有字符轉(zhuǎn)為小寫

    • min_length: int = None: 字節(jié)串的最小長(zhǎng)度

    • max_length: int = None: 字節(jié)串的最大長(zhǎng)度

    • 嚴(yán)格類型,您可以使用StrictStr,StrictBytes,StrictInt,StrictFloat,和StrictBool類型,以防止強(qiáng)制兼容類型

    五、驗(yàn)證器

    使用validator裝飾器可以實(shí)現(xiàn)自定義驗(yàn)證和對(duì)象之間的復(fù)雜關(guān)系。

    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)
        """

    關(guān)于驗(yàn)證器的一些注意事項(xiàng):

    • 驗(yàn)證器是“類方法”,因此它們接收的第一個(gè)參數(shù)值是UserModel類,而不是UserModel

    • 第二個(gè)參數(shù)始終是要驗(yàn)證的字段值,可以隨意命名

    • 單個(gè)驗(yàn)證器可以通過傳遞多個(gè)字段名稱來應(yīng)用于多個(gè)字段,也可以通過傳遞特殊值在所有字段上調(diào)用單個(gè)驗(yàn)證器'*'

    • 關(guān)鍵字參數(shù)pre將導(dǎo)致在其他驗(yàn)證之前調(diào)用驗(yàn)證器

    • 通過each_item=True將導(dǎo)致驗(yàn)證器被施加到單獨(dú)的值(例如List,Dict,Set等),而不是整個(gè)對(duì)象

    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)
        """
    • 關(guān)鍵字參數(shù) always 將導(dǎo)致始終驗(yàn)證,出于性能原因,默認(rèn)情況下,當(dāng)未提供值時(shí),不會(huì)為字段調(diào)用驗(yàn)證器。然而,在某些情況下,始終調(diào)用驗(yàn)證器可能很有用或需要,例如設(shè)置動(dòng)態(tài)默認(rèn)值。

    • allow_reuse 可以在多個(gè)字段/模型上使用相同的驗(yàn)證器

    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)建一個(gè)繼承自BaseSettings的模型,模型初始化程序?qū)L試通過從環(huán)境中讀取,來確定未作為關(guān)鍵字參數(shù)傳遞的任何字段的值。(如果未設(shè)置匹配的環(huán)境變量,則仍將使用默認(rèn)值。)

    這使得很容易:

    • 創(chuàng)建明確定義、類型提示的應(yīng)用程序配置類

    • 自動(dòng)從環(huán)境變量中讀取對(duì)配置的修改

    • 在需要的地方手動(dòng)覆蓋初始化程序中的特定設(shè)置(例如在單元測(cè)試中)

    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 文件設(shè)置變量,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ì)讀取環(huán)境變量,環(huán)境變量將始終優(yōu)先于從 dotenv 文件加載的值。

    pydantic 支持設(shè)置敏感信息文件,同樣有2種方式加載:

    class Settings(BaseSettings):
        ...
        database_password: str
        class Config:
            secrets_dir = '/var/run'

    或者:

    settings = Settings(_secrets_dir='/var/run')

    即使使用 secrets 目錄,pydantic仍會(huì)從 dotenv 文件或環(huán)境中讀取環(huán)境變量,dotenv 文件和環(huán)境變量將始終優(yōu)先于從 secrets 目錄加載的值。

    七、與 mypy 一起使用

    Pydantic 附帶了一個(gè) mypy 插件,向 mypy 添加了許多重要的特定于 pydantic 的功能,以提高其對(duì)代碼進(jìn)行類型檢查的能力。

    例如以下腳本:

    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 會(huì)捕獲其中一個(gè)錯(cuò)誤:

    13: error: "Model" has no attribute "middle_name"

    啟用插件后,它會(huì)同時(shí)捕獲:

    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

    要更改插件設(shè)置的值,請(qǐng)?jiān)?mypy 配置文件中創(chuàng)建一個(gè)名為 的部分[pydantic-mypy],并為要覆蓋的設(shè)置添加鍵值對(duì):

    [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

    感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“python庫pydantic怎么用”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來學(xué)習(xí)!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI