Hub Python 库文档

严格数据类

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

严格数据类

huggingface_hub 包提供了一个用于创建**严格数据类**的实用工具。它们是 Python 标准 dataclass 的增强版本,具有额外的验证功能。严格数据类确保字段在初始化和赋值时都经过验证,这使得它们非常适合数据完整性至关重要的场景。

概述

严格数据类使用 @strict 装饰器创建。它们通过以下方式扩展了常规数据类的功能:

  • 根据类型提示验证字段类型
  • 支持自定义验证器以进行额外检查
  • 可选地允许构造函数中的任意关键字参数
  • 在初始化和赋值时都验证字段

优点

  • 数据完整性:确保字段始终包含有效数据
  • 易用性:与 Python 的 dataclass 模块无缝集成
  • 灵活性:支持自定义验证器以实现复杂的验证逻辑
  • 轻量级:无需 Pydantic、attrs 或类似库等额外依赖

用法

基本示例

from dataclasses import dataclass
from huggingface_hub.dataclasses import strict, as_validated_field

# Custom validator to ensure a value is positive
@as_validated_field
def positive_int(value: int):
    if not value > 0:
        raise ValueError(f"Value must be positive, got {value}")

@strict
@dataclass
class Config:
    model_type: str
    hidden_size: int = positive_int(default=16)
    vocab_size: int = 32  # Default value

    # Methods named `validate_xxx` are treated as class-wise validators
    def validate_big_enough_vocab(self):
        if self.vocab_size < self.hidden_size:
            raise ValueError(f"vocab_size ({self.vocab_size}) must be greater than hidden_size ({self.hidden_size})")

字段在初始化期间进行验证

config = Config(model_type="bert", hidden_size=24)   # Valid
config = Config(model_type="bert", hidden_size=-1)   # Raises StrictDataclassFieldValidationError

字段之间的一致性也在初始化期间进行验证(类级验证)

# `vocab_size` too small compared to `hidden_size`
config = Config(model_type="bert", hidden_size=32, vocab_size=16)   # Raises StrictDataclassClassValidationError

字段在赋值期间也进行验证

config.hidden_size = 512  # Valid
config.hidden_size = -1   # Raises StrictDataclassFieldValidationError

要在赋值后重新运行类级验证,必须显式调用 .validate

config.validate()  # Runs all class validators

自定义验证器

您可以使用 validated_field 为字段附加多个自定义验证器。验证器是一个可调用对象,它接受一个参数并在值无效时引发异常。

from dataclasses import dataclass
from huggingface_hub.dataclasses import strict, validated_field

def multiple_of_64(value: int):
    if value % 64 != 0:
        raise ValueError(f"Value must be a multiple of 64, got {value}")

@strict
@dataclass
class Config:
    hidden_size: int = validated_field(validator=[positive_int, multiple_of_64])

在此示例中,两个验证器都应用于 hidden_size 字段。

附加关键字参数

默认情况下,严格数据类只接受类中定义的字段。您可以通过在 @strict 装饰器中设置 accept_kwargs=True 来允许附加关键字参数。

from dataclasses import dataclass
from huggingface_hub.dataclasses import strict

@strict(accept_kwargs=True)
@dataclass
class ConfigWithKwargs:
    model_type: str
    vocab_size: int = 16

config = ConfigWithKwargs(model_type="bert", vocab_size=30000, extra_field="extra_value")
print(config)  # ConfigWithKwargs(model_type='bert', vocab_size=30000, *extra_field='extra_value')

附加关键字参数会出现在数据类的字符串表示中,但会以 * 为前缀,以强调它们未经验证。

与类型提示集成

严格数据类尊重类型提示并自动验证它们。例如:

from typing import List
from dataclasses import dataclass
from huggingface_hub.dataclasses import strict

@strict
@dataclass
class Config:
    layers: List[int]

config = Config(layers=[64, 128])  # Valid
config = Config(layers="not_a_list")  # Raises StrictDataclassFieldValidationError

支持的类型包括

  • 任意
  • 联合
  • 可选
  • 字面量
  • 列表
  • 字典
  • 元组
  • 集合

以及这些类型的任意组合。如果您需要更复杂的类型验证,可以通过自定义验证器实现。

类验证器

名为 validate_xxx 的方法被视为类验证器。这些方法必须只接受 self 作为参数。类验证器在初始化期间运行一次,紧随 __post_init__ 之后。您可以根据需要定义任意数量的类验证器——它们将按照出现的顺序依次执行。

请注意,当字段在初始化后更新时,类验证器不会自动重新运行。要手动重新验证对象,您需要调用 obj.validate()

from dataclasses import dataclass
from huggingface_hub.dataclasses import strict

@strict
@dataclass
class Config:
    foo: str
    foo_length: int
    upper_case: bool = False

    def validate_foo_length(self):
        if len(self.foo) != self.foo_length:
            raise ValueError(f"foo must be {self.foo_length} characters long, got {len(self.foo)}")

    def validate_foo_casing(self):
        if self.upper_case and self.foo.upper() != self.foo:
            raise ValueError(f"foo must be uppercase, got {self.foo}")

config = Config(foo="bar", foo_length=3) # ok

config.upper_case = True
config.validate() # Raises StrictDataclassClassValidationError

Config(foo="abcd", foo_length=3) # Raises StrictDataclassFieldValidationError
Config(foo="Bar", foo_length=3, upper_case=True) # Raises StrictDataclassFieldValidationError

方法 .validate() 是严格数据类中的保留名称。为防止意外行为,如果您的类已经定义了此方法,将引发 StrictDataclassDefinitionError 错误。

API 参考

@strict

@strict 装饰器通过严格验证增强了数据类。

huggingface_hub.dataclasses.strict

< >

( accept_kwargs: bool = False )

参数

  • cls — 要转换为严格数据类的类。
  • accept_kwargs (bool, 可选) — 如果为 True,则允许在 __init__ 中使用任意关键字参数。默认为 False。

用于为数据类添加严格验证的装饰器。

此装饰器必须在 @dataclass 之上使用,以确保 IDE 和静态类型工具将该类识别为数据类。

可以带参数或不带参数使用

  • @strict
  • @strict(accept_kwargs=True)

示例

>>> from dataclasses import dataclass
>>> from huggingface_hub.dataclasses import as_validated_field, strict, validated_field

>>> @as_validated_field
>>> def positive_int(value: int):
...     if not value >= 0:
...         raise ValueError(f"Value must be positive, got {value}")

>>> @strict(accept_kwargs=True)
... @dataclass
... class User:
...     name: str
...     age: int = positive_int(default=10)

# Initialize
>>> User(name="John")
User(name='John', age=10)

# Extra kwargs are accepted
>>> User(name="John", age=30, lastname="Doe")
User(name='John', age=30, *lastname='Doe')

# Invalid type => raises
>>> User(name="John", age="30")
huggingface_hub.errors.StrictDataclassFieldValidationError: Validation error for field 'age':
    TypeError: Field 'age' expected int, got str (value: '30')

# Invalid value => raises
>>> User(name="John", age=-1)
huggingface_hub.errors.StrictDataclassFieldValidationError: Validation error for field 'age':
    ValueError: Value must be positive, got -1

as_validated_field

用于创建 validated_field 的装饰器。建议用于只有一个验证器的字段,以避免样板代码。

huggingface_hub.dataclasses.as_validated_field

< >

( validator: typing.Callable[[typing.Any], NoneType] )

参数

  • validator (可调用) — 一个方法,它接受一个值作为输入,并在值无效时引发 ValueError/TypeError。

将验证器函数装饰为 validated_field(即带自定义验证器的数据类字段)。

validated_field

创建带有自定义验证的数据类字段。

huggingface_hub.dataclasses.validated_field

< >

( validator: typing.Union[typing.List[typing.Callable[[typing.Any], NoneType]], typing.Callable[[typing.Any], NoneType]] default: typing.Union[typing.Any, dataclasses._MISSING_TYPE] = <dataclasses._MISSING_TYPE object at 0x7fd63e62b910> default_factory: typing.Union[typing.Callable[[], typing.Any], dataclasses._MISSING_TYPE] = <dataclasses._MISSING_TYPE object at 0x7fd63e62b910> init: bool = True repr: bool = True hash: typing.Optional[bool] = None compare: bool = True metadata: typing.Optional[typing.Dict] = None **kwargs: typing.Any )

参数

  • validator (可调用List[可调用]) — 一个方法,它接受一个值作为输入,并在值无效时引发 ValueError/TypeError。可以是验证器列表,以应用多个检查。
  • **kwargs — 要传递给 dataclasses.field() 的附加参数。

创建带有自定义验证器的数据类字段。

对于对字段应用多个检查很有用。如果只应用一个规则,请查看 as_validated_field 装饰器。

错误

class huggingface_hub.errors.StrictDataclassError

< >

( )

严格数据类的基本异常。

class huggingface_hub.errors.StrictDataclassDefinitionError

< >

( )

当严格数据类定义不正确时抛出的异常。

class huggingface_hub.errors.StrictDataclassFieldValidationError

< >

( field: str cause: Exception )

当严格数据类在给定字段的验证失败时抛出的异常。

为什么不使用 pydantic?(或 attrs?或 marshmallow_dataclass?)

  • 请参阅 https://github.com/huggingface/transformers/issues/36329 中关于添加 Pydantic 作为依赖的讨论。这将是一个沉重的添加,需要仔细的逻辑来支持 v1 和 v2。
  • 我们不需要 Pydantic 的大部分功能,特别是那些与自动类型转换、jsonschema、序列化、别名等相关的功能。
  • 我们不需要从字典实例化类的能力。
  • 我们不想修改数据。在 @strict 中,“验证”意味着“检查值是否有效”。在 Pydantic 中,“验证”意味着“类型转换值,可能修改它,然后检查它是否有效”。
  • 我们不需要极速验证。@strict 并非为性能至关重要的高负载而设计。常见用例涉及验证模型配置(执行一次,与运行模型相比可忽略不计)。这使我们能够保持代码最少。
< > 在 GitHub 上更新