Dataclasses and property decorator

前端 未结 10 1659
没有蜡笔的小新
没有蜡笔的小新 2020-12-15 04:43

I\'ve been reading up on Python 3.7\'s dataclass as an alternative to namedtuples (what I typically use when having to group data in a structure). I was wondering if datacla

10条回答
  •  遥遥无期
    2020-12-15 05:08

    Currently, the best way I found was to overwrite the dataclass fields by property in a separate child class.

    from dataclasses import dataclass, field
    
    @dataclass
    class _A:
        x: int = 0
    
    class A(_A):
        @property
        def x(self) -> int:
            return self._x
    
        @x.setter
        def x(self, value: int):
            self._x = value
    

    The class behave like a regular dataclass. And will correctly define the __repr__ and __init__ field (A(x=4) instead of A(_x=4). The drawback is that the properties cannot be read-only.

    This blog post, tries to overwrite the wheels dataclass attribute by the property of the same name. However, the @property overwrite the default field, which leads to unexpected behavior.

    from dataclasses import dataclass, field
    
    @dataclass
    class A:
    
        x: int
    
        # same as: `x = property(x)  # Overwrite any field() info`
        @property
        def x(self) -> int:
            return self._x
    
        @x.setter
        def x(self, value: int):
            self._x = value
    
    A()  # `A(x=)`   Oups
    
    print(A.__dataclass_fields__)  # {'x': Field(name='x',type=,default=,init=True,repr=True}
    

    One way solve this, while avoiding inheritance would be to overwrite the field outside the class definition, after the dataclass metaclass has been called.

    @dataclass
    class A:
      x: int
    
    def x_getter(self):
      return self._x
    
    def x_setter(self, value):
      self._x = value
    
    A.x = property(x_getter)
    A.x = A.x.setter(x_setter)
    
    print(A(x=1))
    print(A())  # missing 1 required positional argument: 'x'
    

    It should probably possible to overwrite this automatically by creating some custom metaclass and setting some field(metadata={'setter': _x_setter, 'getter': _x_getter}).

提交回复
热议问题