【问题标题】:Property setter not working in Python class属性设置器在 Python 类中不起作用
【发布时间】:2019-12-17 09:14:35
【问题描述】:

我正在使用一个我无法控制的类 (MainClass)。我想以 MainClass 为基础,但要添加额外的功能。我已经向我的类(SuperClass)添加了一个属性(索引),但是当我尝试将索引转换为属性时,@.setter 似乎被忽略了。这里有什么问题?

class MainClass(object):
    def __init__(self):
        self.name = 'abc'

class SuperClass(object):
    def __init__(self, main, *args, **kwargs):
        super(SuperClass, self).__init__(*args, **kwargs)
        self.__main = main
        self._index = 0

    def __getattr__(self, attr):
        return getattr(self.__main, attr)

    def __setattr__(self, attr, val):
        if attr == '_SuperClass__main':
            object.__setattr__(self, attr, val)
        return setattr(self.__main, attr, val)

    @property
    def index(self):
        return self._index

    @index.setter
    def index(self, value):
        self._index = value

main_object = MainClass()
super_object = SuperClass(main_object)
print('x', super_object.index, super_object.name)

super_object.index = 3
print('y', super_object.index)

super_object.index += 2
print('z', super_object.index)

【问题讨论】:

  • 您是否有理由不让SuperClass 继承自Main

标签: python oop properties


【解决方案1】:

您定义的__setattr__ 方法优先于@index.setter 简化代码,它应该可以工作:

class MainClass(object):
    def __init__(self):
        self.name = 'abc'

class SuperClass(object):
    def __init__(self, main, *args, **kwargs):
        super(SuperClass, self).__init__(*args, **kwargs)
        self.__main = main
        self._index = 0

    @property
    def name(self):
        return self.__main.name

    @name.setter
    def name(self):
        return self.__main.name

    @property
    def index(self):
        return self._index

    @index.setter
    def index(self, value):
        self._index = value

main_object = MainClass()
super_object = SuperClass(main_object)
print('x', super_object.index, super_object.name)

super_object.index = 3
print('y', super_object.index)

super_object.index += 2
print('z', super_object.index)

输出:

x 0 abc
y 3
z 5

【讨论】:

  • 谢谢。我可以看到它可以工作,但这意味着我必须为 MainClass 中的所有属性设置属性和设置器。这不是微不足道的。没有办法解决吗?我喜欢 setattr 和 getattr 因为它可以解决这个问题。
  • 我想不到。我还没有设法让property.setter__setattr__ 很好地协同工作。无论如何,只使用属性更干净。
【解决方案2】:

__getattr__仅在正常查找机制失败时使用。

然而,

__setattr__ 会在 所有 尝试设置属性时调用。这意味着您当前的定义在 MainClass 实例,而不是访问属性的设置器。

>>> super_object._SuperClass__main.index
2

因为__setattr__ 总是调用setattr(self.__main, attr, val),所以+= 被有效地视为=

__setattr__ 必须处理三种情况:

  1. 属性_SuperClass__main 本身,用于在__init__ 中分配给self.__main 时。
  2. self.__main 上存在的属性的分配
  3. 分配给特定于SuperClass 的属性。

考虑到这一点,尝试

def __setattr__(self, attr, val):
    if attr == '_SuperClass__main':
        super().__setattr__(attr, val)
    elif hasattr(self.__main, attr):
        setattr(self.__main, attr, val)
    else:
        super().__setattr__(attr, val)

【讨论】:

    【解决方案3】:

    我还建议使用更简单的选项,即仅从 MainClass 继承,而不是使用组合和委托:

    class SuperClass(MainClass):
        def __init__(self):
            super().__init__()
            self._index = 0
    
        @property
        def index(self):
            return self._index
    
        @index.setter
        def index(self, value):
            self._index = value
    

    【讨论】:

    • 谢谢,但这对我不起作用(我认为)。我看到 MainClass 对象并创建 SuperClass 对象,我必须分配所有属性(不是吗?)。那会打败对象
    猜你喜欢
    • 1970-01-01
    • 2016-07-30
    • 2012-10-16
    • 1970-01-01
    • 1970-01-01
    • 2021-12-30
    • 1970-01-01
    • 2021-09-10
    • 1970-01-01
    相关资源
    最近更新 更多