Python中被视为引用类型的有什么?
我原以为Python中的序列类型是值类型,结果发现它们其实是引用类型。这意味着,当把一个变量的值赋给另一个新变量时,原来的值不会被复制,而是指向同一个地方。所以我现在想知道,Python中有哪些是值类型?也就是说,哪些类型的变量我可以放心地赋值给新变量,而不用担心它们是引用的?
3 个回答
上面的回答是对的,但我对“引用”这个说法有点不同看法。
像C语言这样的编程语言把变量看作是固定的容器,里面放着值。当你调用一个函数时,会创建一组新的容器,然后把值复制到这些新容器里。有时候,这个容器是通过引用传递的,实际上就成了调用者容器的别名。
而Python则把变量看作是值(对象)的标签(名字)。当你调用一个函数时,会创建一组新的标签,并把它们贴到那些相同的对象上。
在Python中提到“引用”没有意义,因为在其他语言中,“引用”意味着与“值”相对的概念。而Python没有这种对立关系;它只是传递和分配对象。没有什么是被“引用”的。
这可能有点挑剔,但这种术语让C++程序员感到困惑,比如他们听说Python是通过引用传递的,却不明白如何重新分配调用者的名字。
从使用强类型的Swift语言进行iOS开发过来的我,发现Python的引用有点让人困惑,所以我决定做个小比较。以下是总结:
- 在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中,列表/数组是值类型,意味着它们不是引用,而是被复制的。然而在Python中,情况就不同了,在某个索引位置改变值会导致所有引用这个对象的属性都改变,就像上面的例子一样。这一点对于从Swift或其他类似语言过来的人来说非常重要。
那么在Python中我们怎么复制呢?
- 如果你想在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
所有在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