Python中的赋值
我知道在Python中,“变量赋值”其实是把一个名字(变量)绑定到一个对象上,或者重新绑定到另一个对象上。
这就引出了一个问题:在Python中,是否可以进行真正的赋值,比如让一个对象等于另一个对象呢?
我觉得在Python中其实没有这个必要:
不可变对象是不能被“赋值”的,因为它们是不能改变的。
可变对象是可以被赋值的,因为它们可以改变,这样做可能会有用,比如你可能想单独操作一个字典的副本,而不影响原来的字典。不过在这种情况下,Python的做法是提供一个克隆方法,让你可以绑定一个副本,而不是原始对象。
所以我想答案是Python中没有真正的赋值,最好的方式是绑定到一个克隆的对象上。
我只是想分享这个问题,以防我错过了什么重要的内容。
谢谢!
编辑:
Lie Ryan和Sven Marnach的回答都很好,我觉得总体的答案是两者的结合:
对于用户自定义的类型,使用这个方式:
a.dict = dict(b.dict)
(我想如果被赋值的类重新定义了属性访问方法,这样做可能会有问题,但我们就不纠结这些了 :))
对于可变的内置类型(列表和字典),使用它们提供的克隆/复制方法(比如切片、更新等)。
最后,不可变的内置类型是不能被改变的,所以也不能被赋值。
我会选择Lie Ryan的回答,因为这是一个我之前没想到的优雅方式。
谢谢!
3 个回答
我觉得你没有漏掉什么。
我喜欢把Python中的变量想象成贴在盒子上的“标签”,这些标签可以通过赋值来改变位置。而在其他编程语言中,赋值则是改变盒子里的内容(而且赋值符号可以被重载)。
初学者可以在不意识到这些的情况下写出相当复杂的应用程序,但通常这些程序会比较乱。
我觉得你对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
这就引出了一个问题:在Python中,是否可以进行正确的赋值,比如让一个对象等于另一个对象呢?
当然可以:
a.__dict__ = dict(b.__dict__)
这会在C/C++中执行默认的赋值语义(也就是进行浅拷贝赋值)。
这种通用的赋值方式有个问题,就是它并不适合所有人。在C++中,你可以重写赋值运算符,因为你总是需要选择是要完全的浅拷贝、完全的深拷贝,还是介于两者之间的某种方式。