在使用Python中的冻结数据类时,如何使用属性setter [英] How can you use property setter when using frozen dataclasses in Python

查看:0
本文介绍了在使用Python中的冻结数据类时,如何使用属性setter的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只是在玩弄Python数据类和抽象类的概念,我试图实现的基本上是创建一个冻结的数据类,但同时将一个属性作为属性。以下是我执行此操作的代码:

import abc
from dataclasses import dataclass, field

class AbsPersonModel(metaclass=abc.ABCMeta):
    @property
    @abc.abstractmethod
    def age(self):
        ...

    @age.setter
    @abc.abstractmethod
    def age(self):
        ...

    @abc.abstractmethod
    def multiply_age(self, factor):
        ...

@dataclass(order=True, frozen=True)
class Person(AbsPersonModel):
    sort_index: int = field(init=False, repr=False)
    name: str
    lastname: str
    age: int
    _age: int = field(init=False, repr=False)


    def __post_init__(self):
        self.sort_index = self.age


    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, value):
        if value < 0 or value > 100:
            raise ValueError("Non sensical age cannot be set!")
        self._age = value

    def multiply_age(self, factor):
        return self._age * factor



if __name__ == "__main__":
    persons = [
    Person(name="Jack", lastname="Ryan", age=35),
    Person(name="Jason", lastname="Bourne", age=45),
    Person(name="James", lastname="Bond", age=60)
    ]

    sorted_persons = sorted(persons)
    for person in sorted_persons:
        print(f"{person.name} and {person.age}")

当我运行此命令时,收到以下错误:

Traceback (most recent call last):
  File "abstract_prac.py", line 57, in <module>
    Person(name="Jack", lastname="Ryan", age=35),
  File "<string>", line 4, in __init__
  File "abstract_prac.py", line 48, in age
    self._age = value
  File "<string>", line 3, in __setattr__
dataclasses.FrozenInstanceError: cannot assign to field '_age'

如何才能两全其美(数据类并同时使用属性)?

如有任何帮助,将不胜感激。

推荐答案

您可以执行frozen初始值设定项in dataclasses itself does并使用object.__setattr__赋值:

...
    def __post_init__(self):
        object.__setattr__(self, 'sort_index', self.age)
...
    @age.setter
    def age(self, value):
        if value < 0 or value > 100:
            raise ValueError("Non sensical age cannot be set!")
        object.__setattr__(self, '_age', value)
...

根据您的测试用例,它返回

Jack and 35
Jason and 45
James and 60

给我的。

这之所以有效,是因为将数据类设置为frozen会禁用该类的所有者__setattr__,并使其只引发您看到的异常。它的任何__setattr__超类(始终包括object)仍将工作。

这篇关于在使用Python中的冻结数据类时,如何使用属性setter的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆