25

我假设 Python 中的序列类型是值类型。事实证明它们是引用类型(这意味着变量的值在分配给新变量时不会被复制,而是被引用)。所以现在我想知道,Python 中的值类型是什么?也就是说,我可以将 Python 中的哪些类型分配给新变量而不用担心变量被引用?

4

3 回答 3

38

Python 中的所有值都是引用。您需要担心的是类型是否可变。基本的数字和字符串类型,以及tuplefrozenset是不可变的;绑定到其中一种类型的对象的名称只能被反弹,不能被变异。

>>> 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
于 2011-05-28T00:39:16.700 回答
11

来自使用强类型 Swift 语言的 iOS 开发,Python 参考有点混乱,所以我决定做一些比较。以下是摘要:-

  • 在将变量分配给 python 时,说a = 10您只是在这种情况下指向/引用10存储在内存中的对象。因此,如果该对象发生更改,则变量的值a也会更改,但更改a不会更改对象10,这类似于 Swift Primitive 值类型,例如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
于 2020-08-10T03:29:44.640 回答
7

上面的答案是正确的,但我反对“引用”的语义。

类 C 语言将变量视为固定的存储桶,其中放置值。当您调用函数时,会创建一组新的存储桶,并将值复制到其中。有时,存储桶是按引用传递的,实际上成为调用者存储桶的别名。

另一方面,Python 将变量视为值(对象)的标签(名称)。当您调用一个函数时,会创建一组新标签并将其贴在这些相同的对象上。

在 Python 的上下文中提及“引用”是没有意义的,因为在其他所有语言中,“引用”都意味着“值”的替代方案。Python 没有这样的二元性。它只是传递并分配对象。什么都没有提到。

可能是吹毛求疵,但该术语给 C++ 程序员带来了无穷无尽的困惑,例如,他们听到 Python 通过引用传递并且不了解如何重新分配调用者的名称。

于 2011-05-28T04:46:26.013 回答