我是Python的初学者,我无法清楚地理解赋值运算符,例如:
list1 = ["Tom", "Sam", "Jim"]
list2 = list1
以上两个语句将'list1'和'list2'绑定到["Tom", "Sam", "Jim"]
,问题是,
如果是下面的运营商:
list1[1] = "Sam's sister"
,如果赋值语句也被视为绑定,那么list2[1]
仍然与“Sam”相关联,结果是修改list1
不会影响{{ 1}},即使Python呈现相反的输出,另一个问题是list2
是否可以被视为Python中的list1[1]
和list1
变量。
任何人都可以有任何建议吗?
答案 0 :(得分:4)
在您的示例中,标识符list1
和list2
是对同一底层对象的引用(只是同一事物的不同名称)。
id()
可用于查看是否正在引用相同的底层对象。
>>> list1 = ["Tom", "Sam", "Jim"]
>>> list2 = list1
>>> id(list1)
44259368
>>> id(list2)
44259368
要创建已定义列表的副本,请使用[:]
表示法,或马修所提到的deepcopy
。您会注意到,完成此操作后,位置/ ID已更改。
>>> list3 = list1[:]
>>> id(list3)
44280208
关于id命令:
>>> help(id)
Help on built-in function id in module __builtin__:
id(...)
id(object) -> integer
Return the identity of an object. This is guaranteed to be unique among
simultaneously existing objects. (Hint: it's the object's memory address.)
答案 1 :(得分:3)
你是对的,他们不一样。在Python中分配一个裸名称(name = ...
)与分配给其他任何东西的操作不同。特别是它与项目分配(name[0] = ...
)和属性分配(name.attr = ...
)不同。它们都使用等号,但后两个可以用钩子(__setitem__
和__setattr__
)操纵,可以调用任意代码,并且通常在程序员的控制之下。对裸名称的赋值不受Python程序员的控制。你无法影响它的作用;它总是将右侧与左侧的名字绑在一起。
这可能令人困惑,因为人们习惯于认为等号是做出“任务”的原因。但是在Python中,为了理解正在进行的操作,你必须查看等号的左边,看看是什么类型的东西。
答案 2 :(得分:1)
BrenBarn对所有事情都是绝对正确的,但这是另一种看待它的方式,可能更容易理解:
您的第一个语句创建一个包含这些值的列表,然后使list1指向它。第二个语句使list2指向与list1完全相同的内存空间。 (你可以通过在第二个语句之后在它们上面运行id来看到这一点)。
此时,list1和list2基本上都是对同一可变列表的引用。当您更改该列表时,list1和list2仍然引用相同的实际列表,并且使用它们访问它将为您提供相同的功能。
我做了一篇关于相关主题的博客文章recently和Python Conquers the Universe也讨论了类似主题here。
答案 3 :(得分:0)
BrenBam对正在发生的事情有一个很好的解释。 deepcopy
一种解决问题的方法:
>>> from copy import deepcopy
>>> list1 = ["Tom", "Sam", "Jim"]
>>> list2 = deepcopy(list1)
>>> list1[1] = "Sam's sister"
>>> list1
['Tom', "Sam's sister", 'Jim']
>>> list2
['Tom', 'Sam', 'Jim']
良好的编程风格使得实际使用deepcopy
的情况很少见。