类变量的难以理解的行为

时间:2015-02-03 21:39:48

标签: python class

我不得不说我确实没有问题,因为“一切正常”,但我很难理解为什么。

我正在python / urwid中编写脚本。在我的脚本中,我有一个ItemWidget类,其self._w等于3个小部件的urwid.Pile,每个小部件都是urwid.Text行。此外,类ItemWidget有一个属性self.visibility,它是一个包含三个布尔值的列表,另一个是self.rebuild()方法。 init函数是

def __init__ (self, content,vis):
    self.content = content
    self.visibility = vis
    self.rebuild()
    self.__super.__init__(self._w)    

方法rebuild()根据self.visibility()中的值重建self._w。

在脚本的main()函数中,我有一个变量

globalvisibility = [1,1,1]

我创建了一个(大约1000个)ItemWidget实例的列表:

for content in abstracts:                               # (*)
    items.append(ItemWidget(content,globalvisibility))  #

实际上我使用的是变量而不是

for content in abstracts.items():                        
    items.append(ItemWidget(content,[1,1,1]))            

只是因为稍后我将实现将全局可见性保存到文件中。但我认为除了初始化之外,它对任何事情都没有用。

无论如何,在脚本中我经常使用ItemWidget的实例并通过例如

更改其可见性
item.visibility[2] = 0    # (**)

和类似的。到目前为止,一切正常并且符合预期。

这是我的问题。为什么在通过(*)创建ItemWidget的实例后,将变量globalvisibility更改为[0,1,1]会影响所有这些实例?

我不得不说我意外地“发现”它似乎非常有用(我认为要改变ItemWidget的所有实例的可见性原则,我将不得不遍历所有这些实例),但是 - 对我来说 - 非常奇怪。特别是考虑到操作(**)只影响单个实例。

我非常感谢一些解释。

编辑:整个脚本在这里: https://www.dropbox.com/s/a0a4a0asyi5lyxw/tescik.py?dl=0 和示例数据库,如果itemwidget是,我将从中创建实例: https://www.dropbox.com/s/zuwbvggznst85ru/arxiv-2013-05-23.db?dl=0

要运行它,您需要修改第58行以指向数据库。要查看行为,请滚动到某些项目并按Enter键 - 摘要将仅在这些项目上消失,然后按“显示摘要” - 这将重置所有项目的行为。

1 个答案:

答案 0 :(得分:2)

  

为什么在通过(*)创建ItemWidget实例后,将变量globalvisibility更改为[0,1,1]会影响所有这些实例?

因为您在创建所有这些实例时都通过了globalvisibility。所有实例都在vis属性中存储对同一列表的引用。

如果您想避免这种情况,请在__init__方法或创建实例时复制列表:

def __init__ (self, content,vis):
    self.content = content
    self.visibility = vis[:]    # here
    # etc.

或者:

for content in abstracts:
    items.append(ItemWidget(content, globalvisibility[:]))  

你在这里做出的确切选择取决于你是否会想要当前的行为。如果是这样,请将其从__init__()中删除,并在制作实例时进行复制。