动态添加/覆盖property属性的setter和getter

2023-12-27

我需要使用/模仿语法糖语法在子类中动态装饰 getter 和 setter 对方法。

我正在努力解决 setter 的实现问题。

class A:

    def __init__(self, x):
        print('init')
        self.__x = x

    @property
    def x(self):
        print('getter')
        return self.__x

    @x.setter
    def x(self, v):
        print('setter')
        self.__x = v


class Dec:
    def __init__(self):
        print('init - dec')

    def __call__(self, cls):
        c = type('A_Dec', (cls,), {})
        # super-init
        setattr(c, '__init__', lambda sub_self, x: super(type(sub_self), sub_self).__init__(x))
        # getter
        setattr(c, 'x', property(lambda sub_self: super(type(sub_self), sub_self).x))
        
        # setter - see below

        return c

dec_A = Dec()(A)
dec_a = dec_A('p')
print(dec_a.x)

Output

init - dec
init
getter
p

如果我尝试实现 setter 方法Dec, dec_a.x = 'p',通过以下方法我收集了以下错误:

    # setter-statements of __call__

    # Attempt 1
    setattr(c, 'x', property(fset=lambda sub_self, v: super(type(sub_self), sub_self).x(v)))
    # AttributeError: unreadable attribute
    
    # Attempt 2 - auxiliary function
    def m(sub_self, v):
       print('--> ', sf, super(type(sub_self), sub_self))
       super(type(sub_self), sub_self).x = v
    
    # Attempt 2.A
    setattr(c, 'x', eval('x.setter(m)'))
    # NameError: name 'x' is not defined
    
    # Attempt 2.B
    setattr(c, 'x', property(fset=lambda sf, v: m(sf, v)))
    # AttributeError: unreadable attribute
    
    # Attempt 2.C: !! both at once, `fget`and `fset` so, in case, comment the getter in the above code to avoid conflicts
    setattr(c, 'x', property(fget=lambda sub_self: super(type(sub_self), sub_self).x, fset=m))
    # AttributeError: 'super' object has no attribute 'x'
    
    # Attempt 2.D
    p = property(fget=lambda sub_self: super(type(sub_self), sub_self).x, fset=m)
    setattr(c, 'x', p)
    # AttributeError: 'super' object has no attribute 'x'

尝试1引发错误,因为(我猜)用括号设置属性。所以在尝试2我使用了辅助功能,因为lambda不允许初始化、'='语句,同样没有成功。

  • 有没有办法动态模仿属性 getter/setter 装饰器? (可能不需要额外的进口) 还有其他方法吗?

  • 额外:为什么 super 没有属性就不起作用?super().x(v) -> TypeError: super(type, obj): obj must be an instance or subtype of type

EDIT:

  • 额外的答案:来自文档:零参数形式仅适用于类定义内部[...]
  • 使用 python3.9

属性设置器未正确设置。为了形象化这一点,如果没有为属性显式设置 setter,则该属性将变为只读,如下所示有记录的 https://docs.python.org/3/library/functions.html#property.

class Parrot:
    def __init__(self):
        self._voltage = 100000

    @property
    def voltage(self):
        """Get the current voltage."""
        return self._voltage

@property 装饰器将Voltage()方法变成了一个“getter”只读属性同名

假设我们有这个:

class A:
    def __init__(self, x):
        self.__x = x

    @property
    def x(self):
        return self.__x

a = A(123)

print(a.x)  # will display "123"
a.x = 456  # will display "AttributeError: can't set attribute"

在原始代码中,您创建了一个新类型A_Dec。您明确设置了 getter:

# getter
setattr(c, 'x', property(lambda sub_self: super(type(sub_self), sub_self).x))

但是您没有明确设置任何设置器,因此使得x属性只读。这会导致此代码出现错误:

dec_a.x = 'new value!'  # will display "AttributeError: can't set attribute"

解决方案1

不要明确定义 getter。这样,所有访问x将被委托给实际班级A.

解决方案2

如果定义了 getter,那么还要定义 setter。

...
class Dec:
    ...
    def __call__(self, cls):
        ...
        # setter
        x_property = getattr(c, 'x')
        x_setter = getattr(x_property, 'setter')
        setattr(c, 'x', x_setter(lambda sub_self, v: super(type(sub_self), type(sub_self)).x.fset(sub_self, v)))
        ...
...
  • The usage of c.x.setter is as documented https://docs.python.org/3/library/functions.html#property:

    一个属性对象有getter, setter, and deleter可用作装饰器的方法

  • The usage of .fset is as documented https://docs.python.org/3/library/functions.html#property:

    fset是一个设置属性值的函数...返回的属性对象也有属性fget, fset, and fdel对应于构造函数参数。

所以添加以下几行就会成功:

dec_a.x = 'new value!'
print(dec_a.x)

Output:

setter
getter
new value!

更多参考:

  • https://newbedev.com/how-to-call-a-property-of-the-base-class-if-this-property-is-being-overwriting-in-the-driven-class https://newbedev.com/how-to-call-a-property-of-the-base-class-if-this-property-is-being-overwritten-in-the-derived-class
  • https://gist.github.com/Susensio/979259559e2bebcd0273f1a95d7c1e79 https://gist.github.com/Susensio/979259559e2bebcd0273f1a95d7c1e79
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

动态添加/覆盖property属性的setter和getter 的相关文章

  • scipy 将一个稀疏矩阵的所有行附加到另一个稀疏矩阵

    我有一个 numpy 矩阵 想在其中附加另一个矩阵 这两个矩阵的形状为 m1 shape 2777 5902 m2 shape 695 5902 我想将 m2 附加到 m1 以便新矩阵的形状为 m new shape 3472 5902 当
  • 如何以“正确”的方式处理带有空字节的 Python unicode 字符串?

    Question PyWin32 似乎很乐意将 null 终止的 unicode 字符串作为返回值 我想以 正确 的方式处理这些字符串 假设我得到一个像这样的字符串 u C Users Guest MyFile asy x00 x00sy
  • 补丁 - 为什么相对补丁目标名称不起作用?

    我已经从模块导入了一个类 但是当我尝试修补类名而不使用模块作为前缀时 出现类型错误 TypeError Need a valid target to patch You supplied MyClass 例如 以下代码给出了上述错误 imp
  • 如何检查python xlrd库中的excel文件是否有效

    有什么办法与xlrd库来检查您使用的文件是否是有效的 Excel 文件 我知道还有其他库可以检查文件头 我可以使用文件扩展名检查 但为了多平台性我想知道是否有任何我可以使用的功能xlrd库本身在尝试打开文件时可能会返回类似 false 的内
  • Kivy - 有所有颜色名称的列表吗?

    在 Kivy 中 小部件 color属性允许输入其值作为字符串颜色名称 也 例如在 kv file Label color red 是否有所有可能的颜色名称的列表 就在这里 来自Kivy 的文档 https kivy org doc sta
  • 如何在Python中同时运行两只乌龟?

    我试图让两只乌龟一起移动 而不是一只接着另一只移动 例如 a turtle Turtle b turtle Turtle a forward 100 b forward 100 但这只能让他们一前一后地移动 有没有办法让它们同时移动 有没有
  • Python 中的流式传输管道

    我正在尝试使用 Python 将 vmstat 的输出转换为 CSV 文件 因此我使用类似的方法转换为 CSV 并将日期和时间添加为列 vmstat 5 python myscript py gt gt vmstat log 我遇到的问题是
  • 工作日重新订购 Pandas 系列

    使用 Pandas 我提取了一个 CSV 文件 然后创建了一系列数据来找出一周中哪几天崩溃最多 crashes by day bc DAY OF WEEK value counts 然后我将其绘制出来 但当然它按照与该系列相同的排名顺序绘制
  • 在 Django OAuth Toolkit 中安全创建新应用程序

    如何将 IsAdminUser 权限添加到 Django OAuth Toolkit 中的 o applications 视图 REST FRAMEWORK DEFAULT PERMISSION CLASSES rest framework
  • 如何使用文本相似性删除 pandas 数据框中相似(不重复)的行?

    我有数千个数据 这些数据可能相似也可能不相似 使用 python 的默认函数 drop duplicates 并没有真正的帮助 因为它们只检测相似的数据 例如 如果我的数据包含类似以下内容怎么办 嗨 早上好 嗨 早上好 Python 不会将
  • 结构差异 sudo() run('sudo 命令')

    我想知道函数之间有什么区别sudo 和函数run sudo u user smth 文档上有 sudo 在所有运行方式上都是相同的 除了它总是换行 调用 sudo 程序中的给定命令以提供超级用户 特权 但有几次 sudo cmd 提示我输入
  • Django send_mail SMTPSenderRefused 530 与 gmail

    一段时间以来 我一直在尝试使用 Django 从我正在开发的网站接收电子邮件 现在 我还没有部署它 并且我正在使用Django开发服务器 我不知道这是否会影响它 这是我的 settings py 配置 EMAIL BACKEND djang
  • 在系统托盘中隐藏 tkinter 窗口 [重复]

    这个问题在这里已经有答案了 我正在制作一个程序来提醒我朋友的生日 这样我就不会忘记祝福他们 为此 我制作了两个 tkinter 窗口 1 First one is for entering name and birth date 2 Sec
  • Python SSL X509:KEY_VALUES_MISMATCH

    Python HTTPS server from http server import HTTPServer SimpleHTTPRequestHandler import ssl https stackoverflow com a 408
  • 在 Django 查询中使用 .extra(select={...}) 引入的值上使用 .aggregate() ?

    我正在尝试计算玩家每周玩游戏的次数 如下所示 player game objects extra select week WEEK games game date aggregate count Count week 但姜戈抱怨说 Fiel
  • 如何与其他用户一起使用 pyenv?

    如何与其他用户一起使用 pyenv 例如 如果我在用户 test 的环境中安装了 pyenv 则当我以 test 身份登录时可以使用 pyenv 但是 当我以其他用户 例如 root 身份登录时如何使用 pyenv 即使你这么做了 我也会s
  • 从 pandas DataFrame 中删除少于 K 个连续 NaN

    我正在处理时间序列数据 我在从数据帧列中删除小于或等于阈值的连续 NaN 时遇到问题 我尝试查看一些链接 例如 标识连续 NaN 出现的位置以及计数 Pandas NaN 孔的游程长度 https stackoverflow com que
  • 多个对象以某种方式相互干扰[原始版本]

    我有一个神经网络 NN 当应用于单个数据集时 它可以完美地工作 但是 如果我想在一组数据上运行神经网络 然后创建一个新的神经网络实例以在不同的数据集 甚至再次同一组数据 上运行 那么新实例将产生完全错误的预测 例如 对 XOR 模式进行训练
  • 如何为不同操作系统/Python 版本编译 Python C/C++ 扩展?

    我注意到一些成熟的Python库已经为大多数架构 Win32 Win amd64 MacOS 和Python版本提供了预编译版本 针对不同环境交叉编译扩展的标准方法是什么 葡萄酒 虚拟机 众包 我们使用虚拟机和Hudson http hud
  • Apache Beam Pipeline 写表后查询表

    我有一个 Apache Beam Dataflow 管道 它将结果写入 BigQuery 表 然后我想查询该表以获取管道的单独部分 但是 我似乎无法弄清楚如何正确设置此管道依赖性 我编写的新表 然后想要查询 与一个单独的表连接以进行某些过滤

随机推荐