这种问题提法极大可能是受C/C++语言的函数参数传递方式的影响。
事实上:在Python中,函数参数的传递都是引用,python中不存在传值这种参数传递方式。不论传递的数据类型是基本数据类型(如整数、浮点数、字符串等),不可变类型(如元组),可变类型(如列表、字典、集合等),还是混合类型。
或许有人说,不对,基本数据类型和不可变类型,我实现的就是传值,和C/C++语言的传值一样。那么可以看本文后面的代码,查看各对象的id,看看究竟是不是传的都是引用。
对基本数据类型和不可变类型貌似传值的解释:
1.首先基本数据类型就是不可变类型,这样就只剩下对不可变类型的解释。
2.貌似传值的根源在于python的赋值操作的奇葩。所有的python的赋值操作都是左值对右值的引用,右值才是真实的变量。惊讶吧,这与C/C++是否完全相反,C/C++中左值才是真实的变量,右值只是临时值。
3.python不可变类型变量的第二次赋值,不是修改了原有变量,因为原有变量不可修改,而是左值的引用指向了另一个不可变类型对象。试着看看这种情况下新旧左值的id是否一样?不一样吧,反人性吧。
4.对于不可变类型的参数传递,在内部修改时,实际也不是修改了原有变量,而是把形参指向了新的变量,而实参未变化。所以最终结果貌似C/C++语言的传值。
5.不过,尽管传的是引用,但不影响内部使用结果。
6.一切皆源于python的一切皆对象的思想。即使如10, “ddd”, '吃饭'这样的都是永久性对象,而不是临时值。或许这一点决定了python永远不可能永久开机干大活,因为那样的话永久值就会越来越多。
# 基本数据类型作为参数
def modify_number(n):
print(f"Inside the function id: {id(n)}")
n = n + 1 # 修改n的值,不会影响外部的number变量
print(f"Inside the function: {n}")
print(f"Inside the function id: {id(n)}")
number = 10
print(f"Outside the function: {number}")
print(f"Outside the function id: {id(number)}")
modify_number(number)
print(f"Outside the function: {number}") # 外部的number不变
print(f"Outside the function id: {id(number)}\n") # 外部的number的id不变
# 不可变类型作为参数
def modify_tuple(t):
print(f"Inside the function id: {id(t)}")
t = (20, 30) # 尝试修改t,这不会影响外部的my_tuple
print(f"Inside the function: {t}")
print(f"Inside the function id: {id(t)}")
my_tuple = (10, 20)
print(f"Outside the function: {my_tuple}")
print(f"Outside the function id: {id(my_tuple)}")
modify_tuple(my_tuple)
print(f"Outside the function: {my_tuple}") # 外部的my_tuple不变
print(f"Outside the function id: {id(my_tuple)}\n") # 外部的my_tuple的id不变
# 可变类型作为参数
def modify_list(l):
print(f"Inside the function id: {id(l)}")
l.append(30) # 修改列表对象,这会影响外部的my_list
print(f"Inside the function: {l}")
print(f"Inside the function id: {id(l)}")
my_list = [10, 20]
print(f"Outside the function: {my_list}")
print(f"Outside the function id: {id(my_list)}")
modify_list(my_list)
print(f"Outside the function: {my_list}") # 外部的my_list改变了
print(f"Outside the function id: {id(my_list)}\n") # 外部的my_list的id不改变