简单的问题,我缩小了一个问题,当我向对象追加更多数据时,我从一个对象检索到的列表会发生变化。不在名单上。在
有人能帮助我理解python的行为吗?在
class a():
def __init__(self):
self.log = []
def clearLog(self):
del self.log[:]
def appendLog(self, info):
self.log.append(str(info))
def getLog(self):
return self.log
if __name__ == '__main__':
obj = a()
obj.appendLog("Hello")
# get an instance as of this moment....
list = obj.getLog()
print list
obj.appendLog("World")
# print list, BUT we want the instance that was obtained
# before the new appendage.
print list
输出:
^{pr2}$
创建新列表的唯一位置是在构造函数中,其中包含以下语句:
稍后,当您执行以下操作时:
^{pr2}$只需将对同一列表的引用放入一个新变量中(注意,不要使用
list
) 作为变量名,因为它隐藏了类型)。它不会以任何方式创建或克隆列表。如果要克隆它,请执行以下操作:如果合适,还可以使用元组(只读序列):
这可能有助于最大限度地减少关于哪些内容应该修改的混淆。在
看看这个方法:
您已返回对的引用self.log日志并将其分配到列表中。现在它们都指向堆上的同一个列表。当你改变self.log日志,列表指向内存中的同一位置。在
你必须制作一个克隆并将其分配给list,这样两者才能独立。在
当你编码的时候
(忽略——只是一秒钟——使用隐藏的标识符是多么可怕的想法!!!)你的意思是:“make name
list
引用obj.getLog()
返回的完全相同的对象”—正如我们从class a
的代码中知道的那样,obj.log
。当然,既然现在你有一个列表对象有两个名称,当你通过其中一个名称来改变这个对象,所有的改变都会从这两个名称中完全可见,当然,记住,就是只是一个对象,你只是在为它使用多个名称!你从来没有要求拷贝,所以Python当然没有拷贝。在当你想要一份副本而不是原件时,要一份!当您知道您需要的类型(这里是一个列表)时,最好的方法是调用该类型,即:
^{pr2}$当然,如果你选择用你的标识符践踏所有的内置函数——这就是为什么这样的标识符选择是一个坏的想法的一个很好的部分(我再强调也不为过:很难想出比这样的命名更差的样式选择,在你的Python编码中使用)。因此,我已经将标识符重命名为
mylist
(当然,您需要在两个print
语句中重命名它)。在当然,可以使用高度不可读或较慢的方法来弥补对内置标识符
list
正常功能的肆意破坏——例如:或者
或者
但是,到目前为止,最简单、最干净、最受推荐的方法是不要将标识符命名为Python内置的标识符(这也是一个不错的主意,避免像标准Python库中的模块一样命名它们,原因类似,尽管有点弱)。在
相关问题 更多 >
编程相关推荐