我们已经接触过函数(function)的参数(arguments)传递。当时我们根据位置,传递对应的参数。我们将接触更多的参数传递方式。
a = 1def change_integer(a): a = a + 1 return aPRint change_integer(a) #注意观察结果print a #注意观察结果#===(Python中 "#" 后面跟的内容是注释,不执行 )b = [1,2,3]def change_list(b): b[0] = b[0] + 1 return bprint change_list(b) #注意观察结果print b #注意观察结果第一个例子,我们将一个整数变量传递给函数,函数对它进行操作,但原整数变量a不发生变化。
第二个例子,我们将一个表传递给函数,函数进行操作,原来的表b发生变化。
对于基本数据类型的变量,变量传递给函数后,函数会在内存中复制一个新的变量,从而不影响原来的变量。(我们称此为值传递)
但是对于表来说,表传递给函数的是一个指针,指针指向序列在内存中的位置,在函数中对表的操作将在原有内存中进行,从而影响原有变量。 (我们称此为指针传递),指针是C/C++语言中的重要概念,有关指针的概念可以到网上搜索相关资料。 这里记住的是类型是属于对象的,而不是变量。而对象有两种,“可更改”(mutable)与“不可更改”(immutable)对象。在python中,strings, tuples, 和numbers是不可更改的对象,而list,dict等则是可以修改的对象。(这就是这个问题的重点)
当一个引用传递给函数的时候,函数自动复制一份引用,这个函数里的引用和外边的引用没有半毛关系了.所以第一个例子里函数把引用指向了一个不可变对象,当函数返回的时候,外面的引用没半毛感觉.而第二个例子就不一样了,函数内的引用指向的是可变对象,对它的操作就和定位了指针地址一样,在内存里进行修改. stackoverflow
位置传递: 代码如下:
def f(a,b,c): return a+b+cprint(f(1,2,3))在调用f时,1,2,3根据位置分别传递给了a,b,c。
关键字传递
有些情况下,用位置传递会感觉比较死板。关键字(keyWord)传递是根据每个参数的名字传递参数。关键字并不用遵守位置的对应关系。依然沿用上面f的定义,更改调用方式: 代码如下:
print(f(c=3,b=2,a=1))关键字传递可以和位置传递混用。但位置参数要出现在关键字参数之前: 代码如下:
print(f(1,c=3,b=2))参数默认值
在定义函数的时候,使用形如a=19的方式,可以给参数赋予默认值(default)。如果该参数最终没有被传递值,将使用该默认值。 代码如下:
def f(a,b,c=10): return a+b+cprint(f(3,2))print(f(3,2,1))在第一次调用函数f时, 我们并没有足够的值,c没有被赋值,c将使用默认值10. 第二次调用函数的时候,c被赋值为1,不再使用默认值。
包裹传递 在定义函数时,我们有时候并不知道调用的时候会传递多少个参数。这时候,包裹(packing)位置参数,或者包裹关键字参数,来进行参数传递,会非常有用。 下面是包裹位置传递的例子: 代码如下:
def func(*name): print type(name) print namefunc(1,4,6)func(5,6,7,1,2,3)两次调用,尽管参数个数不同,都基于同一个func定义。在func的参数表中,所有的参数被name收集,根据位置合并成一个元组(tuple),这就是包裹位置传递。 为了提醒Python参数,name是包裹位置传递所用的元组名,在定义func时,在name前加*
号。 下面是包裹关键字传递的例子: 代码如下:
与上面一个例子类似,dict是一个字典,收集所有的关键字,传递给函数func。为了提醒Python,参数dict是包裹关键字传递所用的字典,在dict前加**
。 包裹传递的关键在于定义函数时,在相应元组或字典前加*
或**
。
解包裹
*
和**
,也可以在调用的时候使用,即解包裹(unpacking), 下面为例: 代码如下:
在这个例子中,所谓的解包裹,就是在传递tuple时,让tuple的每一个元素对应一个位置参数。在调用func时使用*
,是为了提醒Python:我想要把args拆成分散的三个元素,分别传递给a,b,c。(设想一下在调用func时,args前面没有*
会是什么后果?) 相应的,也存在对词典的解包裹,使用相同的func定义,然后: 代码如下:
在传递词典dict时,让词典的每个键值对作为一个关键字传递给func。
混合 在定义或者调用参数时,参数的几种传递方式可以混合。但在过程中要小心前后顺序。基本原则是,先位置,再关键字,再包裹位置,再包裹关键字,并且根据上面所说的原理细细分辨。 注意:请注意定义时和调用时的区分。包裹和解包裹并不是相反操作,是两个相对独立的过程。
新闻热点
疑难解答