一、可变位置参数

背景引入:

写一个函数,可以对多个数进行累加求和

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)