跳转到主要内容

dataclass 工具,通过多态扩展

项目描述

dataclassish

dataclasses 中提取的工具,扩展到整个Python

Python的 dataclasses 为对象操作提供工具,但仅限于兼容 @dataclass 对象。😢
这个存储库是这些工具的子集,并将它们扩展到可以应用于你想要的任何Python对象!🎉
你可以轻松地为特定对象的方法进行注册,并使用统一的接口进行对象操作。🕶️

例如,

from dataclassish import replace  # New object, replacing select fields

d1 = {"a": 1, "b": 2.0, "c": "3"}
d2 = replace(d1, c=3 + 0j)
print(d2)
# {'a': 1, 'b': 2.0, 'c': (3+0j)}

安装

PyPI platforms PyPI version

pip install dataclassish

文档

Documentation Status

正在制作中。但如果你已经使用过 dataclass,那么你基本上已经知道你需要知道的一切。

入门

在这个例子中,我们将展示如何在处理 @dataclass 对象时,dataclassishdataclasses 完全相同。

from dataclassish import replace
from dataclasses import dataclass


@dataclass
class Point:
    x: float
    y: float


p = Point(1.0, 2.0)
print(p)
# Point(x=1.0, y=2.0)

p2 = replace(p, x=3.0)
print(p2)
# Point(x=3.0, y=2.0)

现在我们将处理一个 dict 对象。请注意,你不能在 dict 对象上使用来自 dataclasses 的工具。

from dataclassish import replace

p = {"x": 1, "y": 2.0}
print(p)
# {'x': 1, 'y': 2.0}

p2 = replace(p, x=3.0)
print(p2)
# {'x': 3.0, 'y': 2.0}

# If we try to `replace` a value that isn't in the dict, we'll get an error
try:
    replace(p, z=None)
except ValueError as e:
    print(e)
# invalid keys {'z'}.

在自定义类型中注册非常简单!让我们创建一个自定义对象并定义 replace 将如何在此对象上操作。

from typing import Any
from plum import dispatch


class MyClass:
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

    def __repr__(self) -> str:
        return f"MyClass(a={self.a},b={self.b},c={self.c})"


@dispatch
def replace(obj: MyClass, **changes: Any) -> MyClass:
    current_args = {k: getattr(obj, k) for k in "abc"}
    updated_args = current_args | changes
    return MyClass(**updated_args)


obj = MyClass(1, 2, 3)
print(obj)
# MyClass(a=1,b=2,c=3)

obj2 = replace(obj, c=4.0)
print(obj2)
# MyClass(a=1,b=2,c=4.0)

添加第二个参数

replace 还可以接受一个第二位置的参数,这是一个指定嵌套替换的字典。例如,考虑以下字典:

p = {"a": {"a1": 1, "a2": 2}, "b": {"b1": 3, "b2": 4}, "c": {"c1": 5, "c2": 6}}

使用 replace,子字典可以通过以下方式更新

replace(p, {"a": {"a1": 1.5}, "b": {"b2": 4.5}, "c": {"c1": 5.5}})
# {'a': {'a1': 1.5, 'a2': 2}, 'b': {'b1': 3, 'b2': 4.5}, 'c': {'c1': 5.5, 'c2': 6}}

相比之下,在纯 Python 中这将是这样:

from copy import deepcopy

newp = deepcopy(p)
newp["a"]["a1"] = 1.5
newp["b"]["b2"] = 4.5
newp["c"]["c1"] = 5.5

这是一个最简单的情况,其中 dict 的可变性允许我们复制整个对象并在之后更新它。注意,我们必须使用 deepcopy 来避免修改子字典。那么如果对象是不可变的呢?

@dataclass(frozen=True)
class Object:
    x: float | dict
    y: float


@dataclass(frozen=True)
class Collection:
    a: Object
    b: Object


p = Collection(Object(1.0, 2.0), Object(3.0, 4.0))
print(p)
Collection(a=Object(x=1.0, y=2.0), b=Object(x=3.0, y=4.0))

replace(p, {"a": {"x": 5.0}, "b": {"y": 6.0}})
# Collection(a=Object(x=5.0, y=2.0), b=Object(x=3.0, y=6.0))

使用 replace,这仍然是一条单行代码。替换任何结构的任何部分,无论嵌套程度如何。

为了区分字典字段和嵌套结构,请使用 F 标记。

from dataclassish import F

replace(p, {"a": {"x": F({"thing": 5.0})}})
# Collection(a=Object(x={'thing': 5.0}, y=2.0),
#            b=Object(x=3.0, y=4.0))

dataclass 工具

dataclasses 除了 replace 之外,还有许多实用函数:fieldsasdictastupledataclassish 支持所有这些函数。

from dataclassish import fields, asdict, astuple

p = Point(1.0, 2.0)

print(fields(p))
# (Field(name='x',...), Field(name='y',...))

print(asdict(p))
# {'x': 1.0, 'y': 2.0}

print(astuple(p))
# (1.0, 2.0)

dataclassish 将这些函数扩展到 dict

p = {"x": 1, "y": 2.0}

print(fields(p))
# (Field(name='x',...), Field(name='y',...))

print(asdict(p))
# {'x': 1.0, 'y': 2.0}

print(astuple(p))
# (1.0, 2.0)

支持自定义对象的实现可以与 replace 类似。

转换器

虽然 dataclasses.field 本身不允许使用转换器(见 PEP 712),但许多类似 dataclasses 的库都允许。一个非常简短、非常不完整的列表包括:attrsequinox。模块 dataclassish.converters 提供了一些有用的转换函数。如果你需要更多,请查看 attrs

from attrs import define, field
from dataclassish.converters import Optional, Unless


@define
class Class1:
    attr: int | None = field(default=None, converter=Optional(int))


obj = Class1()
print(obj.attr)
# None

obj = Class1(a=1)
print(obj.attr)
# 1


@define
class Class2:
    attr: float | int = field(converter=Unless(int, converter=float))


obj = Class2(1)
print(obj.attr)
# 1

obj = Class2("1")
print(obj.attr)
# 1.0

引用

DOI

如果你喜欢使用这个库,并且想要引用你使用的软件,请点击上面的链接。

开发

Actions Status

我们欢迎贡献!

项目详情


下载文件

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

源分布

dataclassish-0.3.1.tar.gz (15.9 kB 查看哈希)

上传时间

构建分布

dataclassish-0.3.1-py3-none-any.whl (11.5 kB 查看哈希)

上传时间 Python 3

由以下支持

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