Python中的赋值

3 投票
3 回答
5719 浏览
提问于 2025-04-16 07:12

我知道在Python中,“变量赋值”其实是把一个名字(变量)绑定到一个对象上,或者重新绑定到另一个对象上。

这就引出了一个问题:在Python中,是否可以进行真正的赋值,比如让一个对象等于另一个对象呢?

我觉得在Python中其实没有这个必要:

  1. 不可变对象是不能被“赋值”的,因为它们是不能改变的。

  2. 可变对象是可以被赋值的,因为它们可以改变,这样做可能会有用,比如你可能想单独操作一个字典的副本,而不影响原来的字典。不过在这种情况下,Python的做法是提供一个克隆方法,让你可以绑定一个副本,而不是原始对象。

所以我想答案是Python中没有真正的赋值,最好的方式是绑定到一个克隆的对象上。

我只是想分享这个问题,以防我错过了什么重要的内容。

谢谢!

编辑:

Lie Ryan和Sven Marnach的回答都很好,我觉得总体的答案是两者的结合:

对于用户自定义的类型,使用这个方式:

a.dict = dict(b.dict)

(我想如果被赋值的类重新定义了属性访问方法,这样做可能会有问题,但我们就不纠结这些了 :))

对于可变的内置类型(列表和字典),使用它们提供的克隆/复制方法(比如切片、更新等)。

最后,不可变的内置类型是不能被改变的,所以也不能被赋值。

我会选择Lie Ryan的回答,因为这是一个我之前没想到的优雅方式。

谢谢!

3 个回答

1

我觉得你没有漏掉什么。

我喜欢把Python中的变量想象成贴在盒子上的“标签”,这些标签可以通过赋值来改变位置。而在其他编程语言中,赋值则是改变盒子里的内容(而且赋值符号可以被重载)。

初学者可以在不意识到这些的情况下写出相当复杂的应用程序,但通常这些程序会比较乱。

4

我觉得你对Python中赋值的描述是对的——我只是想补充一下在特定情况下的克隆和赋值的不同方法。

“复制构造”一个可变的Python内置对象会得到这个对象的一个(浅)副本:

l = [2, 3]
m = list(l)
l is m
--> False

[编辑:正如保罗·麦圭尔在评论中指出的,对于不可变的Python内置对象,“复制构造”的行为是依赖于实现的——你可能会得到一个副本,也可能只是得到同一个对象。但因为这个对象本身是不可变的,所以你也不需要太在意。]

复制构造可以用更通用的方式调用,比如 y = type(x)(x),但这看起来有点难懂。当然,还有一个 copy 模块,可以用来进行浅拷贝和深拷贝。

一些Python对象允许赋值。例如,你可以直接给一个列表赋值,而不需要创建一个新对象:

l = [2, 3]
m = l
l[:] = [3, 4, 5]
m
--> [3, 4, 5]

对于字典,你可以使用 clear() 方法,然后用 update(otherdict) 来给字典赋值,而不需要创建一个新对象。对于一个集合 s,你可以使用

s.clear()
s |= otherset
3

这就引出了一个问题:在Python中,是否可以进行正确的赋值,比如让一个对象等于另一个对象呢?

当然可以:

a.__dict__ = dict(b.__dict__)

这会在C/C++中执行默认的赋值语义(也就是进行浅拷贝赋值)。

这种通用的赋值方式有个问题,就是它并不适合所有人。在C++中,你可以重写赋值运算符,因为你总是需要选择是要完全的浅拷贝、完全的深拷贝,还是介于两者之间的某种方式。

撰写回答