比方说,C++中可以定义一个这样的函数
void foo(const vector<int> & data);
而在 python 中
def foo(data):
...
data_list = [1,2,3]
foo(data_list)
data_list 是可能被修改的。
请问,我在 python 中应该如何写,保证 data_list 不被修改?
感谢大家的解答。如果因为程序前后的要求,data_list 必须是一个列表
那 foo( tuple(data_list) )
性能损失大吗?
Python提供一定程度上的对immutability的支持,但是我个人认为这不是Python语言最初设计考虑进去的,将来好像也不打算支持。Python对于参数传递使用的是Pass By Reference,引用过去的对象是可以被修改的,如果你不想允许修改,Python提供工具给你用,比如Tuple, 比如Property, 但是关于这一点,我想引用我同事的一句我认为很有道理的话,那就是如果你总是想要在一种语言里面寻找另外一种语言才有的特性,那么很有可能从一开始你就不应该选择这门语言。
data_list=(1,2,3)
import copy
adata_list = [1,2,3,4,[5,6]]
d1 = adata_list #这是地址引用
d2 = copy.copy(adata_list) #浅拷贝
d3 = copy.deepcopy(adata_list) #深拷贝
d4 = adata_list[:] #数组拷贝
(d5) = (adata_list) #元组拷贝
adata_list.append('a')
adata_list[4].append('b')
d3.append('d3')
d4.append('d4')
d5.append('d5')
print adata_list #[1,2,3,4,[5,6,'b'],'a','d5']
print d1 #[1,2,3,4,[5,6,'b'],'a','d5']
print d2 #[1,2,3,4,[5,6,'b']]
print d3 #[1,2,3,4,[5,6],'d3']
print d4 #[1,2,3,4,[5,6,'b'],'d4']
print d5 #[1,2,3,4,[5,6,'b'],'a','d5']
def foo(data):
相当于 def foo(new_var = data):
(不是说函数参数格式是这样的,而是说输入的data赋值给一个新的变量new_var),
所以和上面描述的数组拷贝方式是一样的。
浅拷贝会将数组中的元素拷贝过来,如果元素是不可更改数据(比如int,float,string,tuple),则拷贝一个新的副本,如果是可更改数据(list,map)则进行地址拷贝。data_list[:]就是浅拷贝,用slice切片进行的操作应该都是浅拷贝,具体你可以试一试。
所以如果你想让自己传递进去的数据不被更改,那么有如下方案可以实现:
-
data_list
改用data_tuple
或者foo(tuple(data_list))
,但是输入的是tuple,不能直接操作,如果需要操作赋值,还需要转换成list。 - 利用
copy.deepcopy(data_list)
进行深拷贝 - 如果能保证是一维数组,则可以利用
copy.copy(data_list)
或者data_list[:]
进行浅拷贝。
回答完毕~ 啦啦啦~
使用 tuple 这种不可变对象,或者复制一份传递进去。
这样的情况应该比较少。比如调用一个第三方库的接口,但是那个接口因为某种原因会毁掉你传进去的列表,比如 list.sort()
方法。
如果你是为了确保一个可变对象在函数调用后不变的话,那么你应该重写那个函数,然后在文档中注明传入对象会不会变、会怎么变。