重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
这个问题的答案无外乎这几种说法:传值,传引用,对于可变对象是传引用,不可变对象是传值。
10余年的蓝山网站建设经验,针对设计、前端、开发、售后、文案、推广等六对一服务,响应快,48小时及时工作处理。全网整合营销推广的优势是能够根据用户设备显示端的尺寸不同,自动调整蓝山建站的显示方式,使网站能够适用不同显示终端,在浏览器中调整网站的宽度,无论在任何一种浏览器上浏览网站,都能展现优雅布局与设计,从而大程度地提升浏览体验。创新互联建站从事“蓝山网站设计”,“蓝山网站推广”以来,每个客户项目都认真落实执行。
传引用
先看下面这个例子:
def foo(n):
... print id(n)
... n = 3
... print id(n)
n = 2
id(n)
31030000L
foo(n)
31030000L
31029976L
n
2
id(n)
31030000L
由foo中两次输出不相等可以看出,传引用说法并不成立。
传值
来看下面的例子:
def foo(n):
... print n
... n.append(3)
... print n
n = [1, 2, 4, 8]
foo(n)
[1, 2, 4, 8]
[1, 2, 4, 8, 3]
n
[1, 2, 4, 8, 3]
按传值的说法,一个值传进来,在函数内改动并不会影响变量本身的值,上面例子中n变量本身的值也被改变了,说明传值的说法也不对。
3.可变对象传引用,不可变对象传值
相比上面两种说法,这种说法似乎更靠谱,传播也更为广泛,那它到底对不对呢?
def foo(n):
... print id(n)
... n = ['1', '2', '3']
... print id(n)
... print n
n = [1,2,3,4,5,6]
id(n)
35637576
foo(n)
35637576
35916168
['1', '2', '3']
n
[1, 2, 3, 4, 5, 6]
按照可变对象传引用的说法,上面list类型是可变对象,应该传引用,这foo方法中两次调用id应该输出一样的值,更改的结果也应该影响到外部变量,但结果显然不是这样的,这说明,这种说法也是不正确的。
那么Python传值的方法到底是什么样呢?其实Python中的函数参数所遵循的是传对象(call by object),或者叫做穿对象的引用(call by object reference)。在调用函数时,将变量整个对象传入,对于可变对象的修改,在函数内外均可见;而对于不可变对象,因为其并不能真正意义上被赋值,修改是通过生成新的对象来实现的。
下面来一个有趣的例子作为结尾:
def bar(a = []):
... print id(a)
... a.append(7)
... print a
for _ in range(5):
... bar()
#结果输出请自己动手实践,原因应该不难理解
那要看数据类型了,int,float,str这种就是传值,list,dict,类的实例,自定义对象都是穿引用。
下面是示例代码:
def change(int1,float1,str1,dict1,obj1,list1):
int1+=1
float1+=1
str1+='changed'
dict1['none_exist_key']='none_exist_value'
obj1=None
list1.append('change')
class obj:
pass
int1=0
float1=0.0
str1='origin'
dict1={'key':'value'}
obj1=obj()
list1=['only_element']
print(int1)
print(float1)
print(str1)
print(dict1)
print(obj1)
print(list1)
change(int1,float1,str1,dict1,obj1,list1)
print('after change')
print(int1)
print(float1)
print(str1)
print(dict1)
print(obj1)
print(list1)
不明白可追问
python的一切数据类型都是对象。但是python的对象分为不可变对象和可变对象。python的变量是引用,对python变量的赋值是引用去绑定该对象。
可变对象的数据发生改变,例如列表和字典,引用不会更改绑定对象,毕竟本身就是用于增删改查的,频繁地产生新对象必然导致开销巨大,只需要该对象内部变化就行;但对于绑定了不可变对象的引用,对象一旦改变就会使引用绑定新的对象。
这一点也会反应到函数的参数上。python的传值方式是“传对象”引用。python的函数,形参实际上是引用,实参便是对象绑定到该引用上。本质是形参会被作为函数的局部变量,在开辟的函数的栈内存中被声明。
简要来讲:
如果参数是数,则类似值传递,
如果参数是列表和字典,则类似引用传递。
每个对象都会有个id, 可以用id()验证以上说法:
这个函数的参数是列表,是可变对象。
首先你要明白,Python的函数传递方式是赋值,而赋值是通过建立变量与对象的关联实现的。
对于你的代码:
执行 d = 2时,你在__main__里创建了d,并让它指向2这个整型对象。
执行函数add(d)过程中:
d被传递给add()函数后,在函数内部,num也指向了__main__中的2
但执行num = num + 10之后,新建了对象12,并让num指向了这个新对象——12。
如果你明白函数中的局部变量与__main__中变量的区别,那么很显然,在__main__中,d仍在指着2这个对象,它没有改变。因此,你打印d时得到了2。
如果你想让输出为12,最简洁的办法是:
在函数add()里增加return num
调用函数时使用d = add(d)
代码如下:
def add(num):
num += 10
return num
d = 2
d = add(d)
print d