Python从放弃到入门——函数参数argument

参数传递

Python中参数的传递是通过自动将对象(实参)赋值给局部变量名(形参)来实现的。
调用函数时把实参传递给形参从而初始化形参,本质是执行了赋值语句:
形参=实参对象
因此,如果实参对象可变,在函数体内对形参对象的任何修改其实是修改实参。

def f(arg1,arg2):
    print('after initiate:arg1=',arg1,'arg2=',arg2)
    arg1=arg1*2
    arg2.append(4)
    print('after modify:arg1=',arg1,'arg2=',arg2)
i=18
L=[1,2,3]
print('before call f:i=',i,'L=',L)
f(i,L)
print('aftr call f:i=',i,'L=',L)

before call f:i= 18 L= [1, 2, 3]
after initiate:arg1= 18 arg2= [1, 2, 3]
after modify:arg1= 36 arg2= [1, 2, 3, 4]
aftr call f:i= 18 L= [1, 2, 3, 4]

注意:函数调用后,原始L被永久地改变了。
Python的通过复制传入的机制与C++的引用参数作法并不完全相同,但是在实际中,它与C 和其他语言的参数传递模式相当相似。

  • 不可变参数本质上传入了"值"
  • 可变对象本质上传入了"指针"

如没有特殊需要,应避免在函数体中修改可变参数。

参数匹配

所有的函数定义与调用方式参见下表
在这里插入图片描述
下面展开来介绍各种类型的参数定义与调用传参。
Python的函数定义与调用非常灵活,使用时请务必区分定义与调用、形参与实参、以及顺序规则!

位置实参

调用函数时根据形参所在位置传递对应的实参,这样的实参叫位置实参(positional argument)。

def f(a,b,c):
    print('a=',a,'b=',b,'c=',c)
f(2,5,8)
f(5,8,2)
#输出结果为
a= 2 b= 5 c= 8
a= 5 b= 8 c= 2

关键字实参

调用函数时,传递的实参形式可以为:形参名=实参值,这样的实参称为关键字实参(key word argument)。
由于关键字实参指定了形参名,这样能更好的表示传入的实参代表的含义。而且关键字实参的位置可以是任意的。

f(a=2,b=5,c=8)
f(b=5,c=8,a=2)
#输出结果为
a= 2 b= 5 c= 8
a= 2 b= 5 c= 8

当位置实参和关键字实参组合使用时,位置实参必须位于关键字实参之前。

f(2,5,c=8)
a= 2 b= 5 c= 8

f(2,c=8,5) 
SyntaxError: positional argument follows keyword argument

默认值形参

定义函数时,可以给形参设置默认值。在调用时若没有传递参数则使用默认的初始化形参,从而简化调用。

def f1(a,b,c=8):
    print('a=', a, 'b=', b, 'c=', c)
f1(2,6)
f1(2,6,9)
f1(2,6,c=9)
#输出结果为
a= 2 b= 6 c= 8
a= 2 b= 6 c= 9
a= 2 b= 6 c= 9

注意:没有默认值的形参必须位置默认值形参之前。以下函数定义会报语法错误。

def f2(b=5,a):
    print('a=', a, 'b=', b)
SyntaxError: non-default argument follows default argument

当函数有多个参数时,把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数。默认值参数最大的好处是能降低调用函数的难度。

陷阱
Python函数在定义的时候,默认参数L的值就被计算出来了,因此不要把形参的默认值设置为可变类型的对象。否则前一次调用时修改形参默认值会影响下一次调用。

def fun1(L=[]):
    L.append(18)
    print(L)
fun1()
fun1()
fun1()
[18]
[18, 18]
[18, 18, 18]

定义关键字形参

定义函数时,所有形参的某个位置添加了*,*后面所有的形参都被定义为只接收关键字实参的关键字形参(keyword only),有些教程也称为命名关键字参数
在这里插入图片描述

def f(a,b,*,c):
    print('a=', a, 'b=', b, 'c=', c)
f(1,2,c=3)
#输出
a= 1 b= 2 c= 3

f(1,2,3)
TypeError: f() takes 2 positional arguments but 3 were given

关键字形参还可以有默认值,从而简化调用。

def f(a,b,*,c=9):
    print('a=', a, 'b=', b, 'c=', c)
f(1,2)
f(1,2,c=3)
#输出
a= 1 b= 2 c= 9
a= 1 b= 2 c= 3

可变长位置形参的定义与调用

定义函数时,若无法确定位置实参的个数,则可以在形参前添加*号,从而接收0个或任意多个位置实参。位置实参会初始化为一个元组tuple。

def f(*args):
    print(args)
f()
f(1)
f(1,2,3)
#输出结果为
()
(1,)
(1, 2, 3)

个数可变的位置形参通常定义为最后一个形参,如果不是,那么后面的所有形参都被定义为只能接收关键字实参的关键字形参,即上一小节关键字形参的第一种形式。

def f(a,*b,c,d):
    print('a=',a,'b=',b,'c=',c)
#错误的调用方式
f(1,2,3,4,5)
TypeError: f() missing 2 required keyword-only arguments: 'c' and 'd'

#正确的调用方式
f(1,2,3,c=4,d=5)
a= 1 b= (2, 3) c= 4 d= 5

调用函数时,可以在序列前面添加*,从而将序列中的每个元素转换成单独的位置实参。
如前面定义的接收3个位置实参并打印输出的函数。现在有一个列表L=[1,2,3],如何把列表中的元素分别传递给形参呢,只需在调用f时,在参数L的前面添加*号

def f(a,b,c):
	print('a=',a,'b=',b,'c=',c)
L=[1,2,3]
f(*L)
#输出
a= 1 b= 2 c= 3

可变长关键字形参的定义与调用

同长度可变的位置形参一样。如在函数定义时无法确定关键字实参的个数,可以在形参前面添加两个*号,从而接收0个或任意个关键字实参。关键字实参会初始化为一个字典dict。

def f(**kwargs):
    print(kwargs)
f()
f(a=1)
f(a=1,b=2)
#输出
{}
{'a': 1}
{'a': 1, 'b': 2}

由于位置实参必须位于关键字实参之前,因此个数可变的位置形参必须位置个数可变的关键字形参之前。下面的fun函数可以接收任意的位置和关键字实参。
很多内置函数都定义了个数可变的位置和关键字实参,如前面列表中介绍的内置函数sorted
def sorted(*args, **kwargs):

def fun(*args,**kwargs):
    print(args,kwargs)

调用函数时,可以在字典前添加两个*,从而将字典中的每个键值对都转为一个单独的关键字实参。

def f(a,b,c):
    print('a=',a,'b=',b,'c=',c)
#通常我们这样来调用
f(a=1,b=2,c=3)
a= 1 b= 2 c= 3

#也可以将字典一次打包传递
d={'a':1,'b':2,'c':3}
f(**d)
a= 1 b= 2 c= 3

总结

Python的函数具有非常灵活的参数形态,既可以实现简单的调用,又可以传入非常复杂的参数。
函数的定义时可以使用的参数共有5种。但是请注意,
参数定义的顺序必须是:位置参数、默认参数、可变长位置参数、命名关键字参数和可变长关键字参数。
函数调用的顺序必须是:位置参数、关键字参数、*iterable、 **dict。
Python解释器自动按照参数位置和参数名把对应的参数传进去。
请查看下面的函数定义并尝试自行运算返回结果。

def f1(a,b=5,*args,**kwargs):
    print('a=',a,'b=',b,'args=',args,'kwargs=',kwargs)

f1(2,6,7,8,c=9)
f1(2)
#输出
a= 2 b= 6 args= (7, 8) kwargs= {'c': 9}
a= 2 b= 5 args= () kwargs= {}

def f2(a,b=5,*,c,**kwargs):
    print('a=',a,'b=',b,'c=',c,'kwargs=',kwargs)

f2(*(3,6),**{'c':8,'d':10})
f2(3,c=8,d=10)
#输出
a= 3 b= 6 c= 8 kwargs= {'d': 10}
a= 3 b= 5 c= 8 kwargs= {'d': 10}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值