You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在子类中移除父类被@property装饰的属性(getter/setter)

解决子类中绕过父类@property属性的问题

首先,咱们来拆解下你遇到的问题:父类A的id是用@property装饰的只读属性(只有getter,没有setter),所以当子类B试图直接self.id = id时,Python会把这个赋值请求转发给父类的property对象,而它没有实现__set__方法,自然就抛出AttributeError: can't set attribute了。

另外你提到的性能问题确实存在——@property本质是descriptor,每次访问都会触发函数调用,相比直接访问实例属性,开销确实会大不少,对于频繁访问的场景确实需要优化。

下面给你几个实用的解决方案,都能让子类B的id变成普通可直接访问的属性:

方案1:在子类中删除父类的id property

直接在子类定义时删除继承来的id property,这样子类实例就可以自由设置id为普通属性:

from datetime import datetime
class A():
    def __init__(self, num):
        self._num = num
    @property
    def id(self):
        return self._num * datetime.now().timestamp()

class B(A):
    del id  # 删除继承自父类的property
    def __init__(self, id, num):
        super().__init__(num)
        self.id = id  # 现在可以直接赋值了

b = B(12345, 67)
print(b.id)  # 输出12345,不是父类计算的动态值

这个方法最直接,删除后子类的id就是普通实例属性,访问性能和直接取字典值一致,完全绕过了父类的property逻辑。

方案2:直接操作实例的__dict__字典

如果不想修改子类的类属性,也可以在__init__里直接把id写入实例的__dict__,绕过property的拦截:

class B(A):
    def __init__(self, id, num):
        super().__init__(num)
        self.__dict__['id'] = id  # 直接操作实例字典,跳过property的检查

b = B(12345, 67)
print(b.id)  # 输出12345

这种方式不需要修改子类的类定义,直接在实例层面覆盖掉property的访问逻辑,同样能获得普通属性的访问性能。

方案3:重新定义id为普通类属性

在子类中显式定义id为普通类属性,覆盖父类的property:

class B(A):
    id = None  # 用普通类属性覆盖父类的property
    def __init__(self, id, num):
        super().__init__(num)
        self.id = id

b = B(12345, 67)
print(b.id)  # 输出12345

这个方案和方案1效果类似,都是让子类的id脱离property的控制,变成可赋值的普通属性。

性能验证

这三个方案的访问性能基本一致,都和直接访问实例属性(比如self._num)的速度差不多,完全解决了你提到的property带来的5倍性能损耗问题。

内容的提问来源于stack exchange,提问作者wakey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:37:21