Hub Python Library documentation
严格数据类
严格数据类
huggingface_hub 包提供了一个用于创建严格数据类的工具。这些是 Python 标准 dataclass 的增强版本,具备额外的验证功能。严格数据类确保字段在初始化和赋值时均经过验证,使其非常适合数据完整性至关重要的场景。
概述
严格 dataclass 使用 @strict 装饰器创建。它们通过以下方式扩展了常规 dataclass 的功能:
- 基于类型提示验证字段类型
- 支持自定义验证器以进行额外检查
- 在构造函数中可选地允许任意关键字参数
- 在初始化和赋值时验证字段
优势
- 数据完整性:确保字段始终包含有效数据
- 易用性:与 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 dataclasses 仅接受在类中定义的字段。您可以在 @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')数据类的字符串表示中会包含额外的关键字参数,但会以 * 作为前缀,以突出显示这些参数未经验证。
与类型提示的集成
严格 dataclass 会遵循类型提示并自动进行验证。例如:
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支持的类型包括:
- 任意
- Union
- 可选
- 字面量
- 列表
- Dict
- 元组
- 设置
以及这些类型的任意组合。如果您需要更复杂的类型验证,可以通过自定义验证器来实现。
类验证器
名为 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
< source >( accept_kwargs: bool = False )
用于为 dataclass 添加严格验证的装饰器。
此装饰器必须位于 @dataclass 之上,以确保 IDE 和静态类型检查工具将该类识别为 dataclass。
可以带参数或不带参数使用:
@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 -1validate_typed_dict
用于验证字典是否符合 TypedDict 类中定义的类型的方法。
这是针对 TypedDict 的 dataclass 验证等效操作。由于类型化字典永远不会被实例化(仅由静态类型检查器使用),因此必须手动调用验证步骤。
huggingface_hub.dataclasses.validate_typed_dict
< source >( schema: typedata: dict )
验证字典是否符合 TypedDict 类中定义的类型。
在底层,类型化字典会被转换为严格的数据类,并使用 @strict 装饰器进行验证。
示例:
>>> from typing import Annotated, TypedDict
>>> from huggingface_hub.dataclasses import validate_typed_dict
>>> def positive_int(value: int):
... if not value >= 0:
... raise ValueError(f"Value must be positive, got {value}")
>>> class User(TypedDict):
... name: str
... age: Annotated[int, positive_int]
>>> # Valid data
>>> validate_typed_dict(User, {"name": "John", "age": 30})
>>> # Invalid type for age
>>> validate_typed_dict(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 for age
>>> validate_typed_dict(User, {"name": "John", "age": -1})
huggingface_hub.errors.StrictDataclassFieldValidationError: Validation error for field 'age':
ValueError: Value must be positive, got -1as_validated_field
用于创建 validated_field 的装饰器。对于仅包含单个验证器的字段,推荐使用此装饰器以避免样板代码。
huggingface_hub.dataclasses.as_validated_field
< source >( validator: Callable )
将验证器函数装饰为validated_field(即带有自定义验证器的 dataclass 字段)。
validated_field
创建一个带有自定义验证的数据类字段。
huggingface_hub.dataclasses.validated_field
< source >( validator: list[collections.abc.Callable[[typing.Any], None]] | collections.abc.Callable[[typing.Any], None]default: typing.Any = <dataclasses._MISSING_TYPE object at 0x7f9675fda620>default_factory: typing.Any = <dataclasses._MISSING_TYPE object at 0x7f9675fda620>init: bool = Truerepr: bool = Truehash: bool | None = Nonecompare: bool = Truemetadata: dict | None = None**kwargs: typing.Any )
创建一个带有自定义验证器的 dataclass 字段。
适用于对字段应用多项检查。如果只应用一条规则,请查看 as_validated_field 装饰器。
错误
严格数据类的基类异常。
当严格 dataclass 定义不正确时抛出的异常。
类 huggingface_hub.errors.StrictDataclassFieldValidationError
< source >( field: strcause: Exception )
当严格数据类在验证某个字段时失败,会抛出此异常。
为什么不用 pydantic?(或者 attrs?或者 marshmallow_dataclass?)
- 请参阅 https://github.com/huggingface/transformers/issues/36329 中关于将 Pydantic 添加为依赖项的讨论。这将是一个较重的添加,并且需要谨慎的逻辑来同时支持 v1 和 v2。
- 我们并不需要 Pydantic 的大部分功能,尤其是那些与自动类型转换、jsonschema、序列化、别名等相关的功能。
- 我们不需要从字典实例化类的能力。
- 我们不想修改数据。在
@strict中,“validation” 指的是“检查值是否有效”。而在 Pydantic 中,“validation” 指的是“对值进行类型转换(可能会修改该值),然后检查其是否有效”。 - 我们不需要极快的验证速度。
@strict并非为性能至关重要的重负载场景而设计。常见用例包括验证模型配置(仅执行一次,与运行模型相比开销可忽略不计)。这让我们能够保持代码的极简。