【发布时间】:2019-06-27 18:40:43
【问题描述】:
我正在尝试利用 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]
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)
现在如果我做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
我已阅读最相关的帖子: Python property on a list 和 Python decorating property setter with list
但都不适合我的情况:
__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
【问题讨论】:
-
您是否有明确的理由回避
c.s = 5? -
您说“大多数在线示例都假定@property 修饰的属性是一个奇异值,而不是可以由setter 扩展的列表”,但是在这里您永远不会调用setter,这将是通过为
c.s赋值来完成,例如c.s = 1。在这里,您尝试调用c.s的值,因此出现错误。 -
因为
s是一个列表。您可以直接附加到它,例如c.s.append(1)。如果您出于某种原因绝对需要带括号的调用,则需要将list子类化并定义其__call__魔术方法以附加到列表中。 -
@SamuelDion-Girardeau 是的,我同意使用
c.s.append(1)是将新元素附加到当前列表的最佳方式。我阅读了stackoverflow.com/questions/37564798/python-property-on-a-list 的帖子,其中指出“修改属性中的元素,您将获得该属性,然后设置相应的元素。”所以我认为我的@s.setter是这样做的:即获取_s是一个列表的属性,然后通过self._s.append(val)修改它。但是我在这里犯了一个错误并得到了错误。有什么建议吗?谢谢^^ -
@JacquelineP。在您的代码中,您实际上从未使用过 setter,我认为这就是造成混乱的原因。您实际上可以通过从函数中引发错误来测试它,您将永远不会看到错误!使用 setter 并不意味着调用
c.s(5),它意味着分配一个值,例如c.s = 5。如果属性被更明确地命名,我认为这会更明显。例如。假设我们将属性命名为“启用”。吸气剂被称为例如如果你是print(my_object.enabled),如果你是my_object.enabled = True,则是setter,如果你是my_object.enabled(True),不是
标签: python-3.x oop properties