一、可变位置参数
背景引入:
写一个函数,可以对多个数进行累加求和
def fn(iteable):
s=0
for x in iteable:
s+=x
return s
print(fn(range(5)))
输出 10
这个iteable 表示,给一个参数,要给可迭代对象,给元组或者列表类型
参数给fn(1,2,3)是不可以的,如果写fn(1),1是整型,是不能被迭代的
除此之外使用*可以进行调用
def fn1 (*nums):
print(nums,type(nums))
s=0
for x in nums:
s+=x
return s
星号 *:表示可变的在调用的时候使用fn1(1,2,3)
*会把1 2 3 解析为一个元组(1,2,3),nums把输入的3个实参给收集起来了
上面的例子都是按照位置传参数,称为可变位置参数
使用星号之后就变为了可变形参,可以收n个实参,多个实参被收集到一个元组对象中,其中元组是不可变的,传参方式是按照位置传入。
二、可变关键字参数
在形参前面使用两个星号 ** 是可变关键字形参,可以接受多少关键字参数
它将收集到的实参名字和值组织到一个字典(dict)中,字典可变
如果参数名字没有什么太多的意义,对于可变位置参数,请使用*args这是一种习惯。对于可变关键字参数,一般情况下使用**kwargs。使用python的人都知道这两个参数表示什么意思。这是一些名称命名的不成文规定。
def shwoconfig(**kwargs):
print(type(kwargs),kwargs)
会发现输出的是字典类型
def shwoconfig(host='127.0.0.1', password='wadas'):
pass
这种形式就是关键字传参数
使用这种可变关键字参数的情况是,比如有30个参数需要传入函数,就采用**kwargs,由写30个参数变为只写这一个参数就可以了。但是要记住一定要给关键字,就是字典类型的KV对。
def showconfig(*args,**kwargs)
按照位置传参数被 *args接收 类型是元组 接收可变位置参数
按照关键字传参被 **kwargs接收 类型是字典 接收可变关键字参数
要注意:按位置传参必须写在关键字传参数之前,这是语法规则,总之要记住复杂的参数向后放。
三、keyword-only参数
在Python3之后,新增了keyword-only参数,keyword-only参数的含义是在形参定义时,在一个星号*之后,或一个可变位置参数之后,出现的普通参数,就已经不是普通的参数了,称为keyword-only参数。
keyword-only参数,言下之意就是这个参数必须采用关键字传参。
def fn3(*args,x):
print(x,args)
fn(1,2) 这样使用会报错
可以认为上面的例子,args可变位置参数已经截获了所有位置参数,其后的变量x不可能通过位置传参传入了。
同理 **kwargs 会截获所有关键字传参。
keyword-only参数,还要另一种形式:
def fn(*,x,y):
print(x,y)
fn(x=5,y=6)
*星号后所有的普通参数都成了keyword-noly参数,需要给关键字传参数。
**:表示参数结束输入
四、Positional-only 参数
Python 3.8 开始,增加了最后一种形参类型的定义:Positional-only参数
def fn4(a,/,b):
print(a,b)
/ :斜杠之前的参数只能接收位置传参数
有仅位置参数在加/
这个是仅位置参数
fn4(b=2,a=1) 这样传参就会报错
fn4(4,5) 这样就可以
四、参数规则
参数列表的参数顺序一般是:Positional-only、普通参数、缺省参数、可变位置参数、keyword-only参数、可变关键字参数。
规则:
*定义最常用参数为普通参数,可以不提供缺省值,必须由用户提供。注意这些参数的顺序,最常用的先定义。
*将必须使用名称的才能使用的参数,定义为keyword-only参数,要求必须使用关键字传参。
*如果函数有很多参数,无法逐一定义,可使用可变参数。如果需要知道这些参数的意义,则使用可变关键字参数收集。
五、参数解构
def add(x,y):
print(x,y)
return x+y
add(4,5)
t=4,5 封装为了元组 t=(4,5)
add(t)
这个add可以这样使用吗?
不可以的 y的参数没确定
a,b= t
add(a,b) 可以这样用
add(t[0],t[1]) 这样也可以
add(*(4,5)) #调用的时候,参数解构
#把元组拆开 变成4和5
只要是可迭代对象,都可以用 *号解构
*解构之后都是按照顺序传递参数
add({'a':100, 'b':200})
输出 'ab' 是对key进行拼接 字典是无序的,按照输入顺序输出
add(**{'a':(1,2),'b':(100,200)})
** :仅仅能用于字典,是对value的解构
元组的加法是,两个元组进行拼接
上面的写法会报错的, 因为出现了关键字传参数
字典使用**解构,等价于a=(1,2), b=(100,200) 把这两个参数给add。
等价于关键字传参数
add(*range(4,6))
结构出 4 和 5
参数解构只能用于实参传递的时候
def fn(*nums):
s=0
for x in nums:
s+=x
return s
fn(1,3,5)
这个 1 3 5 组成一个元组进入,*nums会把接收的值组成一个元组
fn(range(5)),这里会报错
*nums 这里仅仅接收一个 range(5)这一个对象。变为(rang(5),),
你在去下面做加法肯定出错的
* 转换为按照位置传实参
**{} 转为按照关键字传实参
def fn(a,b,/) /仅仅位置传参数
print(a+b)
fn(**{'a':100,'b':200}) 语法错误
这个是a=100 b=200
六、函数返回值
函数返回值:
不加return 会返回None
def fn(a,b,c):
return a+b, b+c 这里会进行封装
fn(*rang(3)) 0 1 2
这里返回一个元组 (1,3)
返回多个值的时候,会封装成一个元组
max(fn(*range(3))) 等价于 max([0,1,2])
min(*fn(*range(3))) 等价于 min(0,1,2)