python:如何拥有一个属性和一个setter函数来检测值发生的所有更改
我有两个属性来保存列表。每当此列表中的任何项目发生更改时,我希望另一个列表能够自我更新。这包括语句python:如何拥有一个属性和一个setter函数来检测值发生的所有更改,python,properties,Python,Properties,我有两个属性来保存列表。每当此列表中的任何项目发生更改时,我希望另一个列表能够自我更新。这包括语句obj.myProp[3]=5。现在,该语句调用getter函数来获取整个列表,从列表中获取第三项,并将其设置为5。myProp列表已更改,但第二个列表从未更新 class Grid(object): def __init__(self,width=0,height=0): # Make self._rows a multi dimensional array
obj.myProp[3]=5
。现在,该语句调用getter函数来获取整个列表,从列表中获取第三项,并将其设置为5。myProp
列表已更改,但第二个列表从未更新
class Grid(object):
def __init__(self,width=0,height=0):
# Make self._rows a multi dimensional array
# with it's size width * height
self._rows=[[None] * height for i in xrange(width)]
# Make `self._columns` a multi dimensional array
# with it's size height * width
self._columns=[[None] * width for i in xrange(height)]
@property
def rows(self):
# Getting the rows of the array
return self._rows
@rows.setter
def rows(self, value):
# When the rows are changed, the columns are updated
self._rows=value
self._columns=self._flip(value)
@property
def columns(self):
# Getting the columns of the array
return self._columns
@columns.setter
def columns(self, value):
# When the columns are changed, the rows are updated
self._columns = value
self._rows = self._flip(value)
@staticmethod
def _flip(args):
# This flips the array
ans=[[None] * len(args) for i in xrange(len(args[0]))]
for x in range(len(args)):
for y in range(len(args[0])):
ans[y][x] = args[x][y]
return ans
运行示例:
>>> foo=grid(3,2)
>>> foo.rows
[[None, None], [None, None], [None, None]]
>>> foo.columns
[[None, None, None], [None, None, None]]
>>> foo.rows=[[1,2,3],[10,20,30]]
>>> foo.rows
[[1, 2, 3], [10, 20, 30]]
>>> foo.columns
[[1, 10], [2, 20], [3, 30]]
>>> foo.rows[0][0]=3
>>> foo.rows
[[3, 2, 3], [10, 20, 30]]
>>> foo.columns
[[1, 10], [2, 20], [3, 30]]
如果您查看最后三行,这就是实际问题发生的地方。我将子列表的第一项设置为3,但foo.columns
从不更新自身,将3放入其列表中
简言之,如何使一个变量始终更新另一个变量,即使它的子项正在更改
我使用的是Python2.7如果您只返回
行
或列
列表,那么您将永远无法控制更改项目时会发生什么
一种可能是不提供直接获取/设置列表的属性,而是为位于x/y位置的项提供setter/getter
一个好的版本是让\uuuuu setitem\uuuuuuuuuuuuuuu
/\uuuuuuuu getitem\uuuuuuuuuuuuuu
并让它们接受一个元组,这样您就可以使用foo[x,y]
和foo[x,y]=bar
访问元素
另一种方法是在列表周围返回一个包装器,用于检测元素何时被更改,但是您还必须对每个嵌套列表执行此操作。您的问题是您没有在有问题的行上设置
foo.rows
——您得到了它,然后修改了它的一个成员。这不会解雇二传手。对于您提议的API,您需要返回一个包含getter和setter的列表
您最好不要使用rows和columns属性来设置条目,并添加一个\uuu getitem\uuu
方法,如下所示:
class Grid(object):
def __init__(self, width=0, height=0):
self._data = [None] * width * height;
self.width = width
self.height = height
def __getitem__(self, pos):
if type(pos) != tuple or len(pos) != 2:
raise IndexError('Index must be a tuple of length 2')
x, y = pos
if 0 <= x < self.width and 0 <= y < self.height:
return self._data[x + self.width * y]
else:
raise IndexError('Grid index out of range')
def __setitem__(self, pos, value):
if type(pos) != tuple or len(pos) != 2:
raise IndexError('Index must be a tuple of length 2')
x, y = pos
if 0 <= x < self.width and 0 <= y < self.height:
self._data[x + self.width * y] = value
else:
raise IndexError('Grid index out of range')
@property
def columns(self):
return [
[self[x, y] for x in xrange(self.width)]
for y in xrange(self.height)
]
@property
def rows(self):
return [
[self[x, y] for y in xrange(self.height)]
for x in xrange(self.width)
]
我建议你考虑使用。特别是,该方法给出了轴变换的基础矩阵的“视图”,这意味着如果您更改一个,那么另一个也会更改 如果这不符合您的需要,那么我所能看到的使您想要的API工作的唯一方法就是定义“行”和“列”方法,以返回自定义的“视图对象”,这些对象实际上并不存储数据,而是返回到网格对象本身中的一些私有(共享)数据。这些可以是类似列表的,但不支持某些操作(例如,追加或清除)
foo[0, 0] = 3