函数参数详解

 # 函数参数详解
# 一.位置参数
# 二.关键字参数
# 三.默认形参
# 四.可变长参数

参数根据定义阶段和调用阶段分为形参和实参

形参:在定义阶段时括号内的指定的参数就称之为形式参数,本质就是一个名字
实参:在函数调用阶段时括号内传入的参数,是一个实际的值
另外,在调用函数的时候就会自动把形参(变量名)和实参(值)进行绑定
当函数调用结束后,就自动解除绑定了
def func(a,b): # a和b就是形参,a和b实际上就是变量名
print(a)
print(b)
func(1,2) # 1和2就是实参,是被传入的值

因为参数根据定义和调用分为形参和实参,所以无论是位置参数还是关键字参数也都做了详细的划分
例如:位置参数又分为位置形参和位置实参
一.位置参数
位置,值的就是顺序,从左往右来定义的参数就是位置(顺序)参数
需要注意的是,
1.形参必须被传值
2.位置形参和位置实参的数量必须保持一致,不能多传,也不能少传,否则就会报错
3.实参会依照顺序依次赋值给形参
例一
def func(a,b,c) # a,b,c 都是位置形参
print(a,b,c)
func(1,2,3) # 1,2,3 都是位置实参
func(1,2,3,4,5) # 语法错误: 实参与被传值的形参数量不一致

例二
def func(name,age,gender):
print('my name is %s my age is %s my gender is %s' % (name,age,gender))
func('egon',19,'male')


二.关键字参数:在调用阶段指名道姓的为形参赋值,就称之为关键字实参
优点:可以打破传入参数的顺序,关键字实参与形参的位置可以不一致
注意:
1.无论以哪种方式传值,形参都必须被传值
2.关键字实参必须位于位置实参后面
3.不能为同一形参传多次值
4.使用关键字来传参是实参的名字必须与形参的名字一致

(****) 到底是位置参数,还是关键字参数,都是由实参决定的

案例一:
def func(a,b,c):
print(a,b,c)
func(c=10,11,2) # 语法错误: positional argument follows keyword argument(关键字实参出现在了位置实参后面)
func(1,2,a=10) #语法错误: a被传值两次,而c却没有被传值
func(c=10,a=-20,b=5) #正确传参,可以打破顺序限制
func(c=10,a=19,f=20) # 形参与实参的名字不一致所以也会报错

案例二
def register(name,pwd):
print('name is',name)
print('pwd is',pwd)
register(pwd=123123,name='deng') # 可以不用完全按照顺序来传值
register('egon',pwd=123123) # 可以用位置实参和关键字实参混合使用,但前提是关键字实参在位置实参前面

三.默认形参:在定义函数是就已经为形参指定了一个值,那这个形参就是默认形参
例如:def func(name,age,sex='male') # sex 就是默认形参
特点:1.在调用函数的时候不用为默认传参传值,使用参数是就是默认值
2.当然默认形参也可以被传值,这样内部使用的时候就是你传入的值

使用场景:
当一个函数中经常出现重复的值时,就可以将该形参定义为默认形参
好处是可以简化很多重复操作

需要注意:
1.默认形参必须要放在非默认形参后面
2.默认形参在定义阶段就已经固定了
3.不应该将默认形参的默认值定义为可变类型
会导致 每次函数调用都共用同一个默认参数,我们应该将函数设计为独立的功能 每次调用互不干扰
因此,默认形参只能是 str int float tuple

案例一:
def register(name,age,sex='woman'): # 此时要被传值的参数大多是女性,所以可以把性别默认定义为woman
print(name,age,sex)
register('kong',22)
register('luo',25)
register('liu',26)
register('cui',34,sex='man') #但是当有个别案例时,可以自定义传值

案列二:
def reg1(name,sex,hobby,li=[]): # 因为爱好有很多种类,因人而异,所以不应该设置为默认值
li.append(hobby)
print(name,sex)
print(li)
reg1('egon','man','music') # 此时不传值似乎也没有问题,请看下一步操作
reg1('alex','sleep','play') # 只为alex的爱好传了play,可是执行结果却是['music', 'play'] ,
# 因此,把默认参数定义为可变类型,会导致所有的调用者所共享,
正确示范,不应该定义默认形参,
def reg1(name,sex,hobby):
print(name,sex)
print(hobby)
reg1("bgon","man",["music","play"])

四.可变长参数: 是指可以传任意数量的实参
传入实参是为了给形参使用,那就意味着,让形参具备接受任意数量的实参的能力
也就是* 和 **

1.*的使用:
1) 带*的形参: 如案例一
带*的形参可以接受任意数量的实参,那么就收到的实参会被打包成元组类型 如案例一
带*的形参的名字可以随意,但是建议用args,是arguments的缩写
带*的形参不能接收关键字实参
(2) 带*的实参 案例二
在实参前面带*,会自动将*后面的值打散,如案例二,将[9,'yx',10]列表中的每个元素打散,然后按照位置赋值给形参

2.可变长形参和位置形参混合使用 案例三
(1) 当可变长形参出现在位置形参前面,那么后面的位置形参必须使用关键字实参来传值
(2) 当可变长形参出现在位置形参后面,会先按照顺序先给前面的位置形参赋值,最后剩余的就会赋值给可变长args
3.**的使用: 案例四
(1) 形参中带** ,会把关键字实参打包成字典传入
注: **只能接受多出来的关键字实参,**不能接收位置实参
(2) 实参中带**,会把**后的字典(也必须是字典类型)打散,成关键字实参(**{"a":1} 打散为 a = 1)




案例一
def func(*args):
print(args)
func(1)
func(1,2,3,4,5)
func(a=1) # 带*的形参不能接收关键字实参
func(a=1,b=2)
func(a=1,b=2,c=3


案例二
def func(a,b,c,d,e):
print(a,b,c,d,e)
func(1,2,*[9,'yx',10]) # 相当于func(1,2,,9,yx,10)
func(1,2,[3,4,5,6,7]) # 当列表中的元素被打散,
iterable 可迭代的 只要是可以被for循环使用的都是可迭代 字符串 列表 元组 字典 集合

案例三
def func(*args,a,b):
print(a,b,args)
func(1,2,3,4) # 可变长形参出现在位置形参前面,导致1,2,3,41全部传给了args,而a,b没有被赋值,所以会有语法错误
func(1,2,3,4,b=10,a=20) # 当可变长参数出现在位置形参前面时,正确传参形式

def func(a,b,*args):
print(a,b,args)
func(1,2,3,4,5,6,7) # 可变长形参(*args)出现在位置形参后面,先按顺序赋值给位置形参,剩余的全部赋值给*args,打包成元组

案例四
def func(**b):
print(b)
func(x=1,y=2,z='egon') # 将传入的关键字实参打包成字典 {'x': 1, 'y': 2, 'z': 'egon'}
func(1,2,3,4) # 带**的形参不能接受位置实参,只接受关键字实参

# def func(a,b,c,**e):
# print(a,b,c,e) # 先为前面的形参赋值,后续的多余的关键字参数赋值给**
# func(1,c=2,b='egon',rong=438,egon='cool') # 1 egon 2 {'rong': 438, 'egon': 'cool'}

原文地址:https://www.cnblogs.com/dengyanchuan/p/10282301.html