python - 如何最好地实现一个只能调用一次 setter 的属性?

标签 python properties python-decorators

我试图实现一个类属性,其中 setter 只能被调用一次,我想知道如何最好地实现这一点?以及如何使其最“Pythonic”?

我考虑过的选项:

  1. 子类化并扩展内置属性
  2. 装饰属性的 setter。
  3. 添加一个属性,用于保存每个 setter 的设置频率。

还有其他想法吗?

以及如何最好地实现的建议?

最佳答案

如果您经常使用它以及其他属性功能,则对属性进行子类化是合适的。

由于属性的工作方式,这有点棘手 - 当一个人调用时 @prop.setter,创建属性的新实例。下面的子类将起作用。


class FuseProperty(property):
    def setter(self, func):
        def fuse(instance, value):
            name = f"_fuse_{self.fget.__name__}"
            if not getattr(instance, name, False):
                func(instance, value)
            setattr(instance, name, True)
        return super().setter(lambda instance, value: fuse(instance, value))

这是正在使用的。

In [24]: class A:
    ...:     @FuseProperty
    ...:     def a(self):
    ...:         return self._a
    ...:     @a.setter
    ...:     def a(self, value):
    ...:         self._a = value
    ...:

In [25]: a = A()

In [26]: a.a = 23

In [27]: a.a
Out[27]: 23

In [28]: a.a = 5

In [29]: a.a
Out[29]: 23

但是,如果这个“fuse”属性就是您所需要的,并且没有其他代码添加到 getter 和 setter,那么它可能会简单得多:您可以使用相同的机制创建一个全新的“Descriptor”类由 property 使用 - 这可能会好得多,因为您的“fuse”属性可以在一行中构建,而不需要 setter 和 getter 方法。

所需要的只是一个带有 __get____set__ 方法的类 - 我们可以添加 __set_name__ 来自动获取新的属性名称(其中property 本身没有,所以我们从上面的 fget 方法获取名称)

class FuseAttribute:
    def __set_name__(self, owner, name):
        self.name = name
    def __get__(self, instance, owner):
        if instance is None:
            return self
        return getattr(instance, f"_{self.name}")
    def __set__(self, instance, value):
        if not getattr(instance, f"_fuse_{self.name}", False):
            setattr(instance, f"_{self.name}", value)
        # add an else clause for optionally raising an error
        setattr(instance, f"_fuse_{self.name}", True)

并使用它:


In [36]: class A:
    ...:     a = FuseAttribute()
    ...:

In [37]: a = A()

In [38]: a.a = 23

In [39]: a.a
Out[39]: 23

In [40]: a.a = 5

In [41]: a.a
Out[41]: 23

关于python - 如何最好地实现一个只能调用一次 setter 的属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69728924/

相关文章:

python - 我什么时候应该创建多个测试函数,我应该为全局变量使用 pytest fixtures?

windows - 不带参数的Ant设置platforms.JDK_1.6.home

c# - 在运行时设置设置

Python编码技术: class methods that use another method as interface to do system calls

python - 装饰实例方法并从装饰器中调用它

python - 动态加载类并获取引用

python - virtualenvwrapper.user_scripts 找不到 get_env_details

python - Django 中的多对多关系

java - 我可以将 XInclude 与 Java 1.5 XML 属性一起使用吗?

python - 将带有参数的 Python 装饰器合并为一个装饰器