动态添加/覆盖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 的相关文章

  • 如何传递架构以从现有数据帧创建新数据帧?

    要将 schema 传递到 json 文件 我们这样做 from pyspark sql types import StructField StringType StructType IntegerType data schema Stru
  • 类的 IPython 表示

    我正在使用我创建的模块尝试 IPython 但它没有显示类对象的实际表示 相反 它显示类似的内容 TheClass module TheClass name I heavily在这个模块中使用元类 我有真正有意义的类表示 应该向用户显示 是
  • 让 VoiceChannel.members 和 Guild.members 返回完整列表的问题

    每当我尝试使用 VoiceChannel members 或 Guild members 时 它都不会提供适用成员的完整列表 我从文本命令的上下文中获取 VoiceChannel 和 Guild 如下所示 bot command name
  • 计算另一个字符串中多个字符串的出现次数

    在 Python 2 7 中 给定以下字符串 Spot是一只棕色的狗 斑点有棕色的头发 斑点的头发是棕色的 查找字符串中 Spot brown 和 hair 总数的最佳方法是什么 在示例中 它将返回 8 我正在寻找类似的东西string c
  • Gunicorn 工作人员无论如何都会超时

    我正在尝试通过gunicorn运行一个简单的烧瓶应用程序 但是无论我做什么 我的工作人员都会超时 无论是否有针对应用程序的活动 工作人员在我设置任何内容后总是会超时timeout值到 是什么导致它们超时 当我发出请求时 请求成功通过 但工作
  • 我应该使用 Python 双端队列还是列表作为堆栈? [复制]

    这个问题在这里已经有答案了 我想要一个可以用作堆栈的 Python 对象 使用双端队列还是列表更好 元素数量较少还是数量较多有什么区别 您的情况可能会根据您的应用程序和具体用例而有所不同 但在一般情况下 列表非常适合堆栈 append is
  • 从Django中具有外键关系的两个表中检索数据? [复制]

    这个问题在这里已经有答案了 This is my models py file from django db import models class Author models Model first name models CharFie
  • 矩形函数的数值傅里叶变换

    本文的目的是通过一个众所周知的分析傅里叶变换示例来正确理解 Python 或 Matlab 上的数值傅里叶变换 为此 我选择矩形函数 这里报告了它的解析表达式及其傅立叶变换https en wikipedia org wiki Rectan
  • 无法导入 langchain.agents.load_tools

    我正在尝试使用 LangChain Agents 但无法导入 load tools 版本 langchain 0 0 27 我尝试过这些 from langchain agents import initialize agent from
  • python的shutil.move()在linux上是原子的吗?

    我想知道python的shutil move在linux上是否是原子的 如果源文件和目标文件位于两个不同的分区上 行为是否不同 或者与它们存在于同一分区上时的行为相同吗 我更关心的是如果源文件和目标文件位于同一分区上 shutil move
  • 当字段是数字时怎么说...在 mongodb 中匹配?

    所以我的结果中有一个名为 城市 的字段 结果已损坏 有时它是一个实际名称 有时它是一个数字 以下代码显示所有记录 db zips aggregate project city substr city 0 1 sort city 1 我需要修
  • 找到一个数字所属的一组范围

    我有一个 200k 行的数字范围列表 例如开始位置 停止位置 该列表包括除了非重叠的重叠之外的所有类型的重叠 列表看起来像这样 3 5 10 30 15 25 5 15 25 35 我需要找到给定数字所属的范围 并对 100k 个数字重复该
  • 在 Google App Engine 中,如何避免创建具有相同属性的重复实体?

    我正在尝试添加一个事务 以避免创建具有相同属性的两个实体 在我的应用程序中 每次看到新的 Google 用户登录时 我都会创建一个新的播放器 当新的 Google 用户在几毫秒内进行多个 json 调用时 我当前的实现偶尔会创建重复的播放器
  • 带有 LSTM 的 GridSearchCV/RandomizedSearchCV

    我一直在尝试通过 RandomizedSearchCV 调整 LSTM 的超参数 我的代码如下 X train X train reshape X train shape 0 1 X train shape 1 X test X test
  • pandas.read_csv 将列名移动一倍

    我正在使用位于的 ALL zip 文件here http www fec gov disclosurep PDownload do 我的目标是用它创建一个 pandas DataFrame 但是 如果我跑 data pd read csv
  • 将索引与值交换的最快方法

    考虑pd Series s s pd Series list abcdefghij list ABCDEFGHIJ s A a B b C c D d E e F f G g H h I i J j dtype object 交换索引和值并
  • pytest找不到模块[重复]

    这个问题在这里已经有答案了 我正在关注pytest 良好实践 https docs pytest org en latest explanation goodpractices html test discovery或者至少我认为我是 但是
  • python 对浮点数进行不正确的舍入

    gt gt gt a 0 3135 gt gt gt print 3f a 0 314 gt gt gt a 0 3125 gt gt gt print 3f a 0 312 gt gt gt 我期待 0 313 而不是 0 312 有没有
  • NLTK:查找单词大小为 2k 的上下文

    我有一个语料库 我有一个词 对于语料库中该单词的每次出现 我想获取一个包含该单词之前的 k 个单词和该单词之后的 k 个单词的列表 我在算法上做得很好 见下文 但我想知道 NLTK 是否提供了一些我错过的功能来满足我的需求 def size
  • 如何在Python脚本中从youtube-dl中提取文件大小?

    我是 python 编程新手 我想在下载之前提取视频 音频大小 任何 YouTube 视频 gt gt gt from youtube dl import YoutubeDL gt gt gt url https www youtube c

随机推荐