代码之家  ›  专栏  ›  技术社区  ›  BayerSe

替换数据类对象中的属性

  •  26
  • BayerSe  · 技术社区  · 7 年前

    我想替换 dataclass 实例,类似于 namedtuple._replace() ,即制作原始对象的更改副本:

    from dataclasses import dataclass
    from collections import namedtuple
    
    U = namedtuple("U", "x")
    
    @dataclass
    class V:
        x: int
    
    u = U(x=1)
    u_ = u._replace(x=-1)
    v = V(x=1)
    
    print(u)
    print(u_)
    print(v)
    

    这将返回:

    U(x=1)
    U(x=-1)
    V(x=1)
    

    如何在dataclass对象中模拟此功能?

    4 回复  |  直到 7 年前
        1
  •  43
  •   wim    3 年前

    这个 dataclasses 模块具有用于实例上的字段替换的辅助功能( docs )

    from dataclasses import replace
    

    用法不同于 collections.namedtuple ,其中功能是由生成的类型上的方法提供的( 旁注: namedtuple._replace 是文档化/公共API,在名称上使用下划线被作者称为“遗憾”,请参见答案末尾的链接)。

    >>> from dataclasses import dataclass, replace
    >>> @dataclass
    ... class V:
    ...     x: int
    ...     y: int
    ...     
    >>> v = V(1, 2)
    >>> v_ = replace(v, y=42)
    >>> v
    V(x=1, y=2)
    >>> v_
    V(x=1, y=42)
    

    有关设计的更多背景信息,请参阅PyCon 2018年演讲- Dataclasses: The code generator to end all code generators 这个 replace 深入讨论了API,以及 namedtuple 数据类 ,并进行了一些性能比较。

        2
  •  1
  •   Florian Brucker    4 年前

    我知道问题是关于 dataclass ,但如果您使用 attr.s 相反,您可以使用 attr.evolve 而不是 dataclasses.replace :

    import attr
    
    @attr.s(frozen=True)
    class Foo:
        x = attr.ib()
        y = attr.ib()
    
    foo = Foo(1, 2)
    bar = attr.evolve(foo, y=3)
    
        3
  •  -1
  •   ely    7 年前

    dataclass 只是自动创建特殊 __init__ 方法和许多其他基于类型注释属性的“样板”方法。

    创建类后,它与其他类一样,可以覆盖其属性并复制实例,例如:。

    import copy
    
    v_ = copy.deepcopy(v)
    v_.x = -1
    

    根据属性的不同,您可能只需要 copy.copy

        4
  •  -1
  •   Tomerikoo Glorified    4 年前
    @dataclass()
    class Point:
        x: float = dataclasses.Field(repr=True, default=0.00, default_factory=float, init=True, hash=True, compare=True,
                                     metadata={'x_axis': "X Axis", 'ext_name': "Point X Axis"})
        y: float = dataclasses.Field(repr=True, default=0.00, default_factory=float, init=True, hash=True, compare=True,
                                     metadata={'y_axis': "Y Axis", 'ext_name': "Point Y Axis"})
    
    Point1 = Point(13.5, 455.25)
    Point2 = dataclasses.replace(Point1, y=255.25)
    
    print(Point1, Point2)