我曾经认为Python中的序列类型是值类型。事实证明它们是引用类型(这意味着当将变量赋给新变量时,变量的值不会被复制,而是被引用)。因此现在我想知道,在Python中有哪些值类型?也就是说,有哪些类型的变量可以被赋给新变量而不必担心变量被引用?
我曾经认为Python中的序列类型是值类型。事实证明它们是引用类型(这意味着当将变量赋给新变量时,变量的值不会被复制,而是被引用)。因此现在我想知道,在Python中有哪些值类型?也就是说,有哪些类型的变量可以被赋给新变量而不必担心变量被引用?
tuple
和frozenset
都是不可变的;绑定到这些类型对象的名称只能重新绑定,而不能改变。>>> t = 1, 2, 3
>>> t[1] = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
从使用强类型的 Swift 语言开发 iOS 应用的经验来看,Python 参考资料有些令人困惑,因此我决定做一下比较。以下是总结:
a = 10
,实际上是在指向/引用存储在内存中的对象,即 10
。因此,如果该对象发生更改,则变量 a
的值也会更改,但更改 a
不会更改对象 10
,这与 Swift 的原始值类型(如 Int
)类似。为了让这一点更加清晰,这里有一个例子:
# "a" points to an object in this case 10
a = 10
# "b" points to the same object which a points but does not point to a variable a.
b = a
# Now if we change "a" to point to another object in memory say 20.
a = 20
# "b" still points to the old object 10 in other words
# "b == 10" but "a == 20", This is because "b" was never pointing to the variable "a"
# even though we assigned it as "b = a" instead it was pointing to the object 10
# which is # the same as writing b = 10.
让我们来检查一个更复杂的数据结构 List
list1 = [10,20,30,40]
list2 = list1 #[10,20,30,40]
list1 = [3,4]
# list1 ==> [3,4]
# list2 ==> [10,20,30,40]
再次让它表现与Swift和其他类似的语言相同。这里出现了巨大的不同,让我们试着在某个索引处更改值(这变得更加棘手)
list1 = [10,20,30,40]
list2 = list1 #[10,20,30,40]
# change value of list 1 at a certain index say index 0
list1[0] = 500
# If you check again the values of list1 and list2 you will be surprised.
#list1 ==> [500,20,30,40]
#list2 ==> [500,20,30,40]
它们都会改变,因为它们都指向同一个对象,所以更改对象会更改所有 list1
和 list2
。这与其他语言(如Swift)非常令人困惑。在Swift中,List/Array是值类型,这意味着它们不是引用类型,而是被复制传递的,但在Python中则不同,更改特定索引处的值会导致所有引用该对象的属性的值发生更改,就像上面的示例一样。对于从Swift或其他类似语言转来的人来说,这非常重要。
那么我们如何在 python 中复制?
list1 = [10,20,30,40]
list2 = list(list1)
# list1 ==> [10,20,30,40]
# list2 ==> [10,20,30,40]
这样做可以避免 list1
发生变化时产生不必要的影响,list2
将保持不变。
举个例子:
list1[0] = 500
#list1 ==> [500,20,30,40] # Changed
#list2 ==> [10,20,30,40] # Unchanged
t = 1, [2], 3 ; t[1].append(42)
。 - Ned Deilylist()
函数或者对整个列表进行切片(L[:]
)来复制。对于集合,使用set()
函数。对于其他类型,请参考相关文档。需要注意的是,有一些数据类型实际上是无法被克隆的,因为它们代表了外部资源(例如socket
)。 - Ignacio Vazquez-Abrams