python列表上的Python属性设置器

Jac*_* P. 7 oop properties python-3.x

我试图利用Python @property来修改类属性的类属性List.大多数在线示例假设@property修饰的属性是一个奇异值,而不是可以通过setter扩展的列表.

稍微澄清一下问题:我不只是想为属性s分配一个值(int列表的值),而是需要修改它(将新的int附加到当前列表).

我的目的是期望:

c = C()
c.s # [1,2,3] is the default value when instance c initiated.
c.s(5)

c.s # [1,2,3,5]
Run Code Online (Sandbox Code Playgroud)

给出C如下的实施:

class C:
    def __init__(self):
        self._s = [1,2,3]
    @property
    def s(self):
        return self._s
    @s.setter
    def s(self, val):
        self._s.append(val)
Run Code Online (Sandbox Code Playgroud)

如果我这样做c.s(5),我会得到的

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-99-767d6971e8f3> in <module>()
----> 1 c.s(5)

TypeError: 'list' object is not callable

Run Code Online (Sandbox Code Playgroud)

我已经阅读了最相关的帖子: 列表上的Python属性带有列表的Python装饰属性setter

但两者都不适合我的情况: __setitem__可以修改列表的元素,但我想扩展列表.

对于我当前的任务,不能使用全局属性.

在这方面,什么是最好的解决方案?(或者我不应该从一开始就期望@property在可变数据结构上?)谢谢!

------ -----编辑

@Samuel Dion-Girardeau建议

子类列表并定义其调用魔术方法

,但我不确定我理解解决方案.我应该做这样的事情:

class C(list):
     # somewhere when implementing class C
     def __call__(self):
         # even not sure what i need to do here

Run Code Online (Sandbox Code Playgroud)

Sam*_*eau 5

试图在这里总结和举例说明我的评论。希望这可以帮助:

解决方案#1:使用常规属性,并.append()直接

setter 的目的不是扩展属性的值,而是替换它。在这方面,列表与 int 或 string 没有什么不同。在您的情况下,由于该值是一个可变列表,您可以.append()直接在其上调用该方法。

class C():
    def __init__(self):
        self.s = [1, 2, 3]


>>> c = C()
>>> c.s
[1, 2, 3]
>>> c.s.append(1)
>>> c.s
[1, 2, 3, 1]
>>> c.s = [0, 0]
>>> c.s
[0, 0]
Run Code Online (Sandbox Code Playgroud)

解决方案#2:使用属性,并.append()直接

如果在获取/设置时无需检查,则上述解决方案有效s。但是,如果您出于某种原因需要使用属性(例如,您需要进行一些计算或检查,并希望阻止用户将他们想要的任何设置为s),您可以使用属性来实现。

在这种情况下,我将阻止列表中的负数作为验证示例。

class C():
    def __init__(self):
        self._s = [1, 2, 3]
    @property
    def s(self):
        return self._s
    @s.setter
    def s(self, val):
        if any(x < 0 for x in val):
            raise ValueError('No negative numbers here!')
        self._s = val

>>> c = C()
>>> c.s
[1, 2, 3]
>>> c.s.append(1)
>>> c.s
[1, 2, 3, 1]
>>> c.s = [0, 0]
>>> c.s
[0, 0]
>>> c.s = [0, -1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 10, in s
ValueError: No negative numbers here!
Run Code Online (Sandbox Code Playgroud)

请注意此处抛出错误的位置:不是如果我调用c.s(...),您的问题假定它是调用 setter,而是当我分配给 时c.s,使用c.s = ....

另请注意,此类的用户将_s通过 setter 进行间接修改。

解决方案#3:子类list以允许属性可调用

我绝对不推荐这样做,因为它打破了此类用户的所有期望,而且我只是将其作为琐事提供,并且因为它允许您最初要求的行为。

class CallableList(list):
    # This is the method that actually gets called when you `c.s(...)`!
    def __call__(self, *args):
        self.append(*args)

class C():
    def __init__(self):
        self._s = CallableList([1,2,3])
    @property
    def s(self):
        return self._s
    @s.setter
    def s(self, val):
        self._s = CallableList(val)

>>> c = C()
>>> c.s
[1, 2, 3]
>>> c.s(1)
>>> c.s
[1, 2, 3, 1]
>>> c.s = [0, 0]
>>> c.s
[0, 0]
>>> c.s(1337)
>>> c.s
[0, 0, 1337]
Run Code Online (Sandbox Code Playgroud)

请不要这样做,如果您这样做,请确保它无法追溯到我:)