深入解析Python中函数的参数与作用域
|
传递参数 函数传递参数时的一些简要的关键点:
实际上,Python的参数传递模型和C语言的相当相似: 不可变参数”通过值”进行传递。像整数和字符串这样的对象是通过对象引用而不是拷贝进行的,但是因为不论怎么样都不可能在原处改变不可变对象,实际的效果就很像创建了一份拷贝。 传递参数时,传递一个拷贝: L = [1,2] changer(L[:]) 函数内部进行拷贝 def changer(b): b=b[:] 将可变对象转化为不可变对象 L=[1,2] changer(tuple(L)) >>对参数输出进行模拟 def multiple(x,y): x = 2 y = [2,4] return x,y #Return new values in a tuple 这段代码貌似返回了两个值,其实只有一个:一个包含了2个元素的元组,它的括号是可以省略的。 特定的参数匹配模型 >>基础知识
>>匹配语法 在函数的调用中(表中的前4行),简单的通过变量名位置进行匹配,但是使用name=value的形式告诉Python依照变量名进行匹配,这些叫做关键字参数。在调用中使用*sequence或**dict允许我们在一个序列或字典中相应地封装任意多的位置相关或者关键字的对象,并且在将他们传递给函数的时候,将它们解包为分开的、单个的参数。 在函数调用中,参数必须以此顺序出现:任何位置参数(value),后面跟着任何关键字参数(name=value)和*sequence形式的组合,后面跟着**dict形式。 Python内部是使用以下的步骤来在赋值前进行参数匹配的:
>>关键字参数和默认参数的实例 def f(a,b,c): print(a,c) f(1,2,3) #Prints 1,3 关键字参数 关键字参数允许通过变量名进行匹配,而不是通过位置。 f(c=3,b=2,a=1) #Prints 1,3 默认参数 默认参数允许创建函数可选的参数。如果没有传入值的话,在函数运行前,参数就被赋了默认值。 def f(a,c=3): print(a,c) f(1) #Prints 1,3 f(1,4) #Prints 1,4,c=6) #Prints 1,6 关键字参数和默认参数的混合 def func(spam,eggs,totast=0,ham=0): print((spam,ham=0)) func(1,2) #Ouput:(1,0) func(1,ham=1,eggs=0) #Ouput:(1,1) func(spam=1,eggs=0) #Ouput:(1,0) func(toast=1,eggs=2,spam=3) #Ouput:(3,1,3,4) #Ouput:(1,4) >>任意参数的实例 收集参数 在函数定义中,在元组中收集不匹配的位置参数。 def f(*args):print(args) 当这个函数调用时,Python将所有位置相关的参数收集到一个新的元组中,并将这个元组赋值给变量args。因此它是一个一般的元组对象,能够进行索引或迭代。 **特性类似,但是它只对关键字参数有效。将这些关键字参数传递给一个新的字典,这个字典之后将能够通过一般的字典工具进行处理。在这种情况下,**允许将关键字参数转化为字典,你能够在之后使用键调用进行步进或字典迭代。
def f(a,*pargs,**kargs):print(a,pargs,kargs)
f(1,x=1,y=2) #Prints:1 (2,3) {'x':2,'y':1}
解包参数 在最新的Python版本中,我们在调用函数时能够使用*语法。在这种情况下,它与函数定义的意思相反。它会解包参数的集合,而不是创建参数的集合。 def func(a,c,d):print(a,d) args=(1,2) args+=(3,4) func(*args) #Prints 1,4 相似的,在函数调用时,**会以键/值对的形式解包一个字典,使其成为独立的关键字参数。
args={'a':1,'b':2,'c':3}
args['d']=4
func(**args) #Prints 1,4
注意:别混淆函数头部和函数调用时*/**的语法:在头部,它意味着收集任意多的参数,而在调用时,它解包任意数量的参数。 应用函数通用性 if <test>: action,args=func1,(1,) else: action,args=func2,3) ... action(*args) >>Python3.0 Keyword-Only参数 从语法上讲,keyword-only参数编码为命名的参数,出现在参数列表中的*args之后。所有这些参数都必须在调用中使用关键字语法来传递。 我们也可以在参数列表中使用一个*字符,来表示一个函数不会接受一个变量长度的参数列表,而是仍然期待跟在*后面的所有参数都作为关键字传递。 def kwonly(a,*,c) kwonly(1,c=3,b=2) #Prints:1,3 kwonly(c=3,a=1) #Prints:1,3 kwonly(1,3) #Error! 上述代码中,b和c必须按照关键字传递,不允许其他额外的位置传递。 另外,默认函数仍然对keyword-only参数有效,所以,实际上,带有默认值的keyword-only参数都是可选的,但是,那些没有默认值的keyword-only参数真正地变成了函数必需的keyword-only参数。 排序规则 最后,注意keyword-only参数必须在一个单个星号后指定,而不是两个星号――命名的参数不能出现在**args任意关键字形式的后面,并且一个**不能独自出现在参数列表中。这两种做法将产生错误。 def kwonly(a,**pargs,c) #Error! def kwonly(a,**,c) #Error! 这就意味着,在一个函数的头部,keyword-only参数必须编写在**args任意关键字形式之前,且在*args任意位置形式之后。 实际上,在函数调用中,类似的排序规则也是成立的:当传递keyword-only参数的时候,它们必须出现在一个**args形式之前。keyword-only参数可以编写在*arg之前或者之后,并且可能包含在**args中:
def f(a,*b,c=6,**d):print(a,d)
f(1,*(2,3),**dict(x=4,y=5)) #Prints:1 (2,3) 6 {'x':4,'y':5}
f(1,y=5),c=7) #Error!
f(1,c=7,y=5)) #Prints:1 (2,3) 7 {'x':4,y=5,c=7)) #Prints:1 (2,'y':5}
Python作用域 在一个Python程序只用变量名时,Python创建、改变或查找变量名都是在所谓的命名空间(一个保存变量名的地方)中进行的。也就是说,在代码中变量名被赋值的位置决定了这个变量名能被访问到的范围,也即决定了它存在于哪个命名空间中。 除了打包程序之外,函数还为程序增加了一个额外的命名空间层:默认情况下,一个函数所有变量名都是与函数的命名空间相关联的。这意味着: 一个在def内的定义的变量能够在def内的代码使用,不能在函数的外部应用这样的变量名。 (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
