python:如何拥有一个属性和一个setter函数来检测值发生的所有变化 [英] python: how to have a property and with a setter function that detects all changes that happen to the value

查看:64
本文介绍了python:如何拥有一个属性和一个setter函数来检测值发生的所有变化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个包含列表的属性.每当此列表中的任何项目发生更改时,我都希望其他列表自行更新.这包括语句 obj.myProp[3]=5.现在,此语句调用 getter 函数来获取整个列表,从列表中获取第三项,并将其设置为 5.myProp 列表已更改,但第二个列表从未更新.

类网格(对象):def __init__(self,width=0,height=0):# 使 self._rows 成为一个多维数组# 与它的大小宽度 * 高度self._rows=[[None] * x 范围内 i 的高度(宽度)]# 使 `self._columns` 成为一个多维数组# 与它的大小高度 * 宽度self._columns=[[None] * x 范围内 i 的宽度(高度)]@财产定义行(自我):# 获取数组的行返回 self._rows@rows.setter定义行(自我,价值):#当行改变时,列被更新self._rows=值self._columns=self._flip(value)@财产定义列(自我):# 获取数组的列返回 self._columns@columns.setter定义列(自我,价值):#当列改变时,行被更新self._columns = 值self._rows = self._flip(value)@静态方法定义_翻转(参数):# 这会翻转数组ans=[[None] * len(args) for i in xrange(len(args[0]))]对于范围内的 x(len(args)):对于范围内的 y(len(args[0])):ans[y][x] = args[x][y]返回答案

示例运行:

<预><代码>>>>foo=grid(3,2)>>>foo.rows[[无,无],[无,无],[无,无]]>>>foo.columns[[无,无,无],[无,无,无]]>>>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 放入其列表中.

简而言之,我如何制作一个始终更新另一个变量的变量,即使它的子项正在更改?

我使用的是 Python 2.7

解决方案

你的问题是你没有 setting foo.rows 在违规行 - 你'重新获取,然后修改其中的一个成员.这不会触发二传手.使用您提议的 API,您需要返回一个还附加了 getter 和 setter 的列表.

最好不要使用行和列属性来设置条目,并添加一个像这样的 __getitem__ 方法:

类网格(对象):def __init__(self, width=0, height=0):self._data = [无] * 宽度 * 高度;self.width = 宽度self.height = 高度def __getitem__(self, pos):如果 type(pos) != tuple 或 len(pos) != 2:raise IndexError('索引必须是长度为 2 的元组')x, y = 位置如果 0 <= x 

折线变成:

foo[0, 0] = 3

I have a two properties which holds lists. Whenever any item in this list changes, I would like the other list to update itself. This includes the statement obj.myProp[3]=5. Right now, this statement calls the getter function to get the whole list, gets the third item from the list, and sets that to 5. the myProp list is changed, but the second list never gets updated.

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

Example run:

>>> 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]]

If you look at the last three lines, this is where the actual problem occurs. I set the first item of the sublist to three, but foo.columns never updates itself to put the 3 in its list.

So in short, how do I make a variable that always updates another variable, even when it's subitem is being changed?

I'm using Python 2.7

解决方案

Your problem is that you're not setting foo.rows on the offending line - you're getting it, and then modifying one of it's members. This isn't going to fire the setter. With the API you're proposing, you would need to return a list that has getters and setters attached as well.

You'd do better to not use the rows and columns properties to set entries, and add a __getitem__ method like this:

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)
        ]

The broken line then becomes:

foo[0, 0] = 3

这篇关于python:如何拥有一个属性和一个setter函数来检测值发生的所有变化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆