Python 将啥视为引用类型?
Posted
技术标签:
【中文标题】Python 将啥视为引用类型?【英文标题】:What does Python treat as reference types?Python 将什么视为引用类型? 【发布时间】:2011-09-03 18:33:54 【问题描述】:我假设 Python 中的序列类型是值类型。事实证明它们是引用类型(这意味着变量的值在分配给新变量时不会被复制,而是被引用)。所以现在我想知道,Python 中的值类型是什么?也就是说,我可以将 Python 中的哪些类型分配给新变量而不用担心变量被引用?
【问题讨论】:
【参考方案1】: 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
【讨论】:
为了完整起见,应该注意的是,虽然元组是不可变的,但其中包含的任何可变对象都可能发生变异:t = 1, [2], 3 ; t[1].append(42)
为了完整起见,您能否补充一下我将如何复制/克隆一个值?
这取决于类型。对于列表,您可以将其传递给 list()
或对整个事物进行切片 (L[:]
)。对于集合,将其传递给set()
。对于其他类型,请参阅相关文档。请注意,有 一些 类型根本无法有效地克隆,仅仅因为它们代表外部资源(例如socket
)。【参考方案2】:
来自使用强类型 Swift 语言的 ios 开发,Python 参考有点混乱,所以我决定做一个小比较。这是摘要:-
当将变量分配给 python 说a = 10
时,您只是在这种情况下指向/引用对象 10
,它存储在内存中。因此,如果该对象发生更改,则变量 a
的值也会更改,但更改 a
不会更改对象 10
,这与 Int
等 Swift Primitive 值类型类似。
为了说明这一点,这里举个例子:-
# "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
【讨论】:
很高兴我能帮上忙 :) 这很有帮助。我来自 Swift,当 Python 的赋值运算符在列表中的表现不如预期时,我感到很惊讶。 FWIW - 我相信你知道这一点 - 似乎列表有一个 .copy() 方法,它也会生成一个未附加到原始列表的副本。【参考方案3】:上面的答案是正确的,但我反对“引用”的语义。
类 C 语言将变量视为固定的存储桶,其中放置值。当您调用函数时,会创建一组新的存储桶,并将值复制到其中。有时,存储桶是通过引用传递的,实际上成为调用者存储桶的别名。
另一方面,Python 将变量仅视为值(对象)的标签(名称)。当您调用一个函数时,会创建一组新标签并将其贴在这些相同的对象上。
在 Python 的上下文中提及“引用”是没有意义的,因为在所有其他语言中,“引用”都意味着“值”的替代。 Python 没有这样的二元性。它只是传递并分配对象。没有任何东西被提到。
也许是吹毛求疵,但该术语给 C++ 程序员带来了无穷无尽的困惑,例如听到 Python 通过引用传递,不明白如何重新分配调用者的名字。
【讨论】:
Python 按值传递,但值是引用。 这很愚蠢。传递的值不是对对象的引用;它们是对象。 也许这篇文章 (bit.ly/4Cjmn0) 和与之相关的 SO 问题 (bit.ly/3fRXW) 可以对此有所了解。我发现文章中使用的术语有助于让事情变得不那么混乱。另外,虽然我看到你关于参考的观点,但我不同意。在这个词的一般意义上,标签或名称是一种参考。当我使用你的名字时,我是指你。 我完全同意你的观点,有时我会为此争论不休 ;-) 如果你知道 C 引用是什么,那么你就知道 Python 不能通过这些,因为这会使所有对象可变的。我将 Python 的模式称为“别名调用”,只是为了避免这样的问题。另一方面,认为 Python 通过引用传递对象也有效:该引用由 string(虚拟机上的对象的名称)而不是数字(真实硬件上的内存地址)给出)。这两种观点都有意义,了解它们都比单独的一种更有帮助:-)以上是关于Python 将啥视为引用类型?的主要内容,如果未能解决你的问题,请参考以下文章