Python中被视为引用类型的有什么?

31 投票
3 回答
25355 浏览
提问于 2025-04-16 18:30

我原以为Python中的序列类型是值类型,结果发现它们其实是引用类型。这意味着,当把一个变量的值赋给另一个新变量时,原来的值不会被复制,而是指向同一个地方。所以我现在想知道,Python中有哪些是值类型?也就是说,哪些类型的变量我可以放心地赋值给新变量,而不用担心它们是引用的?

3 个回答

8

上面的回答是对的,但我对“引用”这个说法有点不同看法。

像C语言这样的编程语言把变量看作是固定的容器,里面放着值。当你调用一个函数时,会创建一组新的容器,然后把值复制到这些新容器里。有时候,这个容器是通过引用传递的,实际上就成了调用者容器的别名。

而Python则把变量看作是值(对象)的标签(名字)。当你调用一个函数时,会创建一组新的标签,并把它们贴到那些相同的对象上。

在Python中提到“引用”没有意义,因为在其他语言中,“引用”意味着与“值”相对的概念。而Python没有这种对立关系;它只是传递和分配对象。没有什么是被“引用”的。

这可能有点挑剔,但这种术语让C++程序员感到困惑,比如他们听说Python是通过引用传递的,却不明白如何重新分配调用者的名字。

22

从使用强类型的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]

它们都会改变,因为它们都指向同一个对象,所以改变这个对象会影响到 list1list2。这对于来自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
48

所有在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

撰写回答