1. Python中的参函数参数传址还是传值?
在其他语言(C/C++等)中函数参数有传地址或传值的说法。具体就是如果是传地址形式,那么在函数中修改参数的值,将影响到实参的值,而传值形式,则在函数中修改参数的值将不会影响到实参的值,因为函数中参数是实参的拷贝。那么在Python中有什么异同呢?看一个例子:
from ctypes import *
import os.path
import sys
def test(c):
print "test before "
print ("c=%d" %c)
print id(c)
c+=2
print "test after +"
print ("c=%d" %c)
print id(c)
return c
a=2
print "main before call test"
print ("a=%d" %a)
print id(a)
print "####main before call test"
n=test(a)
print "main afterf call test"
print ("a=%d" %a)
print id(a)
print "####main after call test"
输出为:
main before call test
a=2
28499024
####main before call test
test before
c=2
28499024
test after +
c=4
28498976
main afterf call test
a=2
28499024
####main after call test
[root@localhost python]#
我结合输出解析下例子。
1) 输出为a=2,因为我们开始将a赋值为2
2)a的id为28499024,这个没什么好说的
3)进入test函数,c=2,id为28499024,跟a一样,说明是将a和c是同一个对象,这里看其实是传了地址
4)做加法运算后,c=4,id为28498976,已经改变了
5)回到main函数,a=2,id为28499024,没有改变
通过这个例子说明,Python函数传递方式是地址传递,但是如果函数中试图对参数进行修改,将有新的对象接收修改后的值
上面例子是一个方面,我们再看下一个例子:
from ctypes import *
import os.path
import sys
def test(c):
print "test before "
print c
print id(c)
c[0]+=2
print "test after +"
print c
print id(c)
return c
a=[1,2,3]
print "main before call test"
print a
print id(a)
print "####main before call test"
n=test(a)
print "main afterf call test"
print a
print id(a)
print "####main after call test"
输出为:
main before call test
[1, 2, 3]
139757398355408
####main before call test
test before
[1, 2, 3]
139757398355408
test after +
[3, 2, 3]
139757398355408
main afterf call test
[3, 2, 3]
139757398355408
####main after call test
[root@localhost python]#
前面没什么好解析的,传递到函数中的都是同一个对象,但是操作c[0]+=2后,并没有生成新的对象来接收操作值,而是原来的对象。从test函数返回后,打印的列表值,也受到了影响。
所以对于Python函数参数的传递形式,我们不能用C/C++等语言函数参数值传递/地址传递的方式去理解
在Python中参数类型有mutable(可变的) 和 inmutable (不可变的)
mutable : list(列表) ,dict(字典)
inmutable : int , string , float ,tuple...
参数传递到函数内部,对于可变类型,直接修改;对于不可变类型,用新的对象接收修改后的值。
其实,在函数参数传递,本质上还是赋值语句,在Python中,所谓赋值其实是传递引用,一旦对象进行修改,就会区分mutable(直接修改) 和inmutable (新建对象接收修改值),对于inmutable 对象,操作后发生变化,则由新的对象来承接。
如下:
a=2
b=3
c=[1,2]
print id(a)
print id(b)
print id(c)
a+=a
print id(a)
a+=a
print id(a)
a=b
print id(b)
a=c
print id(a)
print c
c[0]=3
print c
print id(c)
输出:
22486096
22486072
139734120213896
22486048
22485952
22486072
139734120213896
[1, 2]
[3, 2]
139734120213896
c赋值给a后,a和c指向同一个对象。才a(不可变)进行修改,生成新的对象来接收,a指向新的对象;对c(可变对象)进行修改,承接修改结果的还是c
2 Python中函数默认参数
先看个例子:
from ctypes import *
import os.path
import sys
def f(x,l=[],arg=None):
print id(l)
print id(arg)
for i in range(x):
l.append(i*i)
print(l)
print id(l)
print id(arg)
print('---1---')
f(4)
print('---2---')
f(5)
print('---3---')
f(5,[])
输出:
---1---
140259558485456
140259557097248
[0, 1, 4, 9]
140259558485456
140259557097248
---2---
140259558485456
140259557097248
[0, 1, 4, 9, 0, 1, 4, 9, 16]
140259558485456
140259557097248
---3---
140259558482792
140259557097248
[0, 1, 4, 9, 16]
140259558482792
140259557097248
[root@localhost python]#
可以看到对于有默认参数的函数,如果有传递参数,则用传递的参数替换,如果没有则使用默认的参数,需要注意的是:对于mutable(可变参数),每次不传递参数的调用都将使用同一个对象,所以一般是不建议将mutable(可变参数)设置为默认参数的
3 可变参数args和kargs惯例先看例子:
from ctypes import *
import os.path
import sys
def test(*args,**kargs):
print type(args)
print id(args)
print args
print type(kargs)
print id(kargs)
print kargs
test("aaaa","bbbb","cccc",aaaa="aaaa",bbbb="bbbb")
print "*"*100
test("a","b","c",a="a",b="b")
输出:
<type 'tuple'>
140355262179120
('aaaa', 'bbbb', 'cccc')
<type 'dict'>
25255472
{'aaaa': 'aaaa', 'bbbb': 'bbbb'}
****************************************************************************************************
<type 'tuple'>
140355262179120
('a', 'b', 'c')
<type 'dict'>
25255472
{'a': 'a', 'b': 'b'}
结合输出和代码我们可以得到:
1) args本质上是tuple(元组),kargs本质上是dict(字典)
2)tuple不可修改,但是两次调用显示的args的id是一样的
我们做下面修改(返回args):
from ctypes import *
import os.path
import sys
def test(*args,**kargs):
print type(args)
print id(args)
print args
print type(kargs)
print id(kargs)
print kargs
return args
aa = test("aaaa","bbbb","cccc",aaaa="aaaa",bbbb="bbbb")
print id(aa)
print "*"*100
bb = test("a","b","c",a="a",b="b")
print id(bb)
输出:
<type 'tuple'>
140463185413936
('aaaa', 'bbbb', 'cccc')
<type 'dict'>
27319728
{'aaaa': 'aaaa', 'bbbb': 'bbbb'}
140463185413936
****************************************************************************************************
<type 'tuple'>
140463185414816
('a', 'b', 'c')
<type 'dict'>
27319728
{'a': 'a', 'b': 'b'}
140463185414816
再做下面修改(返回kargs):
from ctypes import *
import os.path
import sys
def test(*args,**kargs):
print type(args)
print id(args)
print args
print type(kargs)
print id(kargs)
print kargs
return kargs
aa = test("aaaa","bbbb","cccc",aaaa="aaaa",bbbb="bbbb")
print id(aa)
print type(aa)
print "*"*100
bb = test("a","b","c",a="a",b="b")
print id(bb)
print type(bb)
输出:
<type 'tuple'>
139682381502256
('aaaa', 'bbbb', 'cccc')
<type 'dict'>
26025360
{'aaaa': 'aaaa', 'bbbb': 'bbbb'}
26025360
<type 'dict'>
****************************************************************************************************
<type 'tuple'>
139682381502256
('a', 'b', 'c')
<type 'dict'>
25269056
{'a': 'a', 'b': 'b'}
暂时还不知道解释,后面再看看~