跳转到主要内容

记录类

项目描述

Test records codecov

记录

Records是一个Python库,它使得强大的结构类变得简单。

最简单的示例

Records的一个特性是,默认情况下,它所做的操作不比namedtuple或dataclass多。

from records import RecordBase

class Point(RecordBase):
    x: float
    y: float
    z: float = 0.0

p0 = Point(x=0, y=0)
print(p0)  # Point(x=0, y=0)
print(p0.x)  # 0
# note that no type checking or coercion is performed
print(type(p0.y))  # int
# by default, the type hints are not even run
p1 = Point(x="hello", y="world", z="1.0")
print(p1.y)  # world
print(type(p1.z))  # str

检查、强制转换和验证

有时我们希望在将参数输入结构之前执行一些额外的处理。为此,我们有三个步骤:类型检查、强制转换和验证

  • 类型检查是第一步,也是最简单的一步,它只是检查参数是否是我们期望的类型。如果不是,那么我们将执行强制转换。
  • 类型强制转换只有在类型检查失败的情况下才会发生,它将尝试将参数转换为期望的类型。正如人们所预期的那样,有许多潜在的强制转换器,因此它们必须单独添加。
  • 验证在类型检查或类型强制转换成功后发生。到这时,我们已经确定输入是正确类型的,我们想要确保/操作其值。

这些方法通过字段描述,使用Annotation类型提示(Annotation是Python 3.9中引入的,但已被records向后移植以用于旧版本)

这三个步骤在文档中有更详细的说明,现在我们将展示一些简短的示例

from typing import List
from records import RecordBase, Annotated, check, check_strict, Loose, Within, Eval

class Person(RecordBase):
    first_name: str  # no coercion or checking here, this is what we call a "hollow" field
    last_name: Annotated[str, check]  # now we will raise a TypeError if anyone tries to enter a non-string last_name  
    year_of_birth: Annotated[int, check_strict]  # we will raise a TypeError if year_of_birth isn't exactly an int (so passing True will throw an error)
    lucky_number: Annotated[int, check, Loose]  # the "Loose" built-in coerser will simply call the destination type with the input as an argument, so that using `lucky_number="7"` would be equivalent to `lucky_number=int("7")`
    number_of_children: Annotated[int, check, Within(ge=0)]  # the Within built-in validator ensures the value is within stated bounds (in this case, at least zero)
    # field tokens can even be more complex in case of nested field types
    names_of_children: Annotated[List[Annotated[int, check, Eval]], check]  # the list will be checked to be a list, and each item individually will be checked or coerced to be an int using the built-in Eval coercer.
    
    # validators can also be added after declaration with pre_bind
    @classmethod
    def pre_bind(cls):
        @cls.last_name.add_validator
        def no_bad_words(last_name):
            # we want to remove some words from the last name
            return last_name.replace('richard', '*******')

    # we can also add some more pre-processing on an entire instance with "post_new"
    def post_new(self):
        if len(self.names_of_children) != self.number_of_children:
            raise ValueError("children mismatch")

解析

Records还可以从各种Python原语解析。包括从dict、json和通用命名空间解析。

from types import SimpleNamespace
from records import RecordBase, check

class User(RecordBase, default_type_check=check):
    name: str
    password: str
    age: int = 18
    

print(User.from_mapping({"name": "richard", "password": "swordfish"}))
print(User.from_json('{"name": "richard", "password": "swordfish"})'))
n = SimpleNamespace(user="rich", password="ard", age= 7)
print(User.from_instance(n))

# parsing can even be done if you expect misnamed fields!
from_upper_dict = User.from_mapping.select(keys_to_rename=[('user','name')], keys_to_remove=['favorite_color'])
print(from_upper_dict({'user':'richard', 'password': 'pw', 'favorite_color': 'red'}))

您还可以定义自己的解析器,甚至可以在构造中使用它们!

from math import sqrt
from records import RecordBase, check, SelectableFactory, parser

class Point(RecordBase, default_type_check=check):
    x: float
    y: float
    z: float = 0
    
    @parser
    @SelectableConstructor
    @classmethod
    def from_tuple(cls, v):
        return {'x':v[0], 'y':v[1], 'z':v[2] if len(v) > 2 else 0}

    @property
    def norm(self):
        return sqrt(self.x**2 + self.y**2 + self.z**2)

p = Point([2,3,6])
print(p.norm)  # 7

导出

Records还可以导出到各种格式(与解析相同)。

from records import RecordBase, check

class Point(RecordBase, default_type_check=check):
    x: float
    y: float
    z: float

p = Point(x=2, y=3, z=6)
print(p.to_dict())
print(p.to_pickle())
#  again, we can select to change the keys
print(
    p.to_json.select(keys_to_add=[('w',0)])()
)

项目详情


下载文件

下载您平台对应的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。

源代码分发

recordclasses-0.0.1.tar.gz (30.4 kB 查看哈希值)

上传时间 源代码

构建分发

recordclasses-0.0.1-py3-none-any.whl (35.6 kB 查看哈希值)

上传时间 Python 3

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面