1 Fork me on GitHub

python函数进阶与参数处理

可变参数
可变参数也称为不定长参数
传入函数中实际参数可以是任意多个
常见形式
    *args
    **kwargs

 


 

外溢知识部分:----------------------------------------------------------------------


很多时候,我们的函数需要参数,有多种情况的参数:

def func1(x,y): —普通形参
def func2(x,y=1): —普通形参 和 位置参数,也叫缺省参数,有默认值
def func3(x,y,z,…): — 不定长参数
def func4(x=?,y=?,z=?,…) —不定长位置参数 ,参数键值由传入的实参决定
def func4(x,y=1,z,a,b,?=?) —前面所有情况混合
那么关于不定长参数,普通形参已经不可以满足了,这时候,*args 和 **kwargs,就可以解决问题。

python参数的分类:
外连接:https://blog.csdn.net/weixin_38492159/article/details/107778320
外连接2:https://www.jb51.net/article/222288.htm


看个例子1:

def func1(x,*args,**kwargs):
    print(x)
    print(args)   //在函数中使用时需要将*去掉
    print(kwargs)
func1(100,2,'a',('x','y'), name='jack',age=20,)

返回:

可以看出,除去普通参数 ‘x’对应的 ‘100’, 后面的 2, ‘a’, ('x','y'), 都被 print(args)给打印出来了,
由此可见,
*args以 元祖 的形式接收所有的不定长的参数,不管是什么类型,都一概收入囊中。
而到了 name='jack',age=20 这里,*args已经不能接收了,因为不知道 name 和 name的值 jack要以怎样的形式安放,这时候**kwargs就体现了其特殊作用了。
**kwargs``以 字典 的形式 接收所有位置参数,然后将 等号左边作为字典的键,等号右边作为字典的值,这样通过打印,就得到了 {'name': 'jack', 'age': 20}, 而其长度也是不定长的。有多少接收多少。

 

例子2:
那么思考一下,如果我的实参是一个字典,直接传入会怎样?

def func1(*args,**kwargs):
    print(args)   #  在函数中使用时需要将*去掉
    print(kwargs)
dict_1 = {'a':1,'b':2}
func1(dict_1)

返回:

 

 再一次印证了 *args 以 元祖 的形式接收所有的不定长的参数,即使是字典,都一概收入囊中。

 

例子3:这里参数为字符串;字符串被分解为字符,并以字符形式放进一个元祖中

def func1(*args,**kwargs):
    print(args)   # 在函数中使用时需要将*去掉
    print(kwargs)
str_1 = 'hello'    
func1(*str_1)    # 变量前加了个*号,  字符串被分解成了一个个字符,并以字符串的形式放进了元祖里面

返回:

 
例子4:这里参数为元祖, 当带*和不带*的枚举:

 

例子5:这里参数为列表,带*和不带*枚举:

 返回:

 

例子6:这里参数是字典,进行序列解包,只会获取字典的键放进一个元祖里:

 

例子7这里参数为数字时,进行序列解包,会报错提示:

 报错提示:

 


总结:

所以我们看出,*args 可以将 * 解包后的元素放进元祖里,如果没有解包,那么是将整个当成一个元素放进元祖中,
而 * 可解包的必须是可迭代对象,字符串元祖字典等都可以, 整型类的不可以。

 

-----------------那么下面我们看看两颗星的,**

例子1:这里对元祖进行测试:

显然 ** 后面不能够加 元祖,必须要是一个mapping 对象,通过测试,其他类型也不行,但是字典可以。
我之前认为,*是解包,**是解包两次。 如果元祖中再套一个元祖是否可行?

 

 

 实时证明是不行的。


例子2:字典

 

字典倒是可以 通过**解包,但是这好像和传进去一个字典没啥区别,我为啥要用 **kwags 接收参数呢?
所以我们不再用 **kwags 接收 ** 解包后的参数
那么再来看下面一个例子

 

原来解包后的字典可以按 键的同名实形参取到对应的值,而且形参的位置也没有规定,都会取到键对应的值。
但是有一个问题,如果形参变量名与实参字典的键不同名呢?看下面这例子:

 

所以得出结论:使用 **字典 解包,当做函数参数传入,函数的形参必须与字典的键同名,否则会报错。

 

例子3:
那我们再思考一下,*解包字典,可以拿到其对应的键,是不是也可以当做函数参数传入呢?是否也需要相同变量名呢?

 

 我们可以看到,使用 *字典 可以将键传入函数,而函数形参可以任意名字。


例子4:

最后我们考虑一下, 当普通参数、位置参数与 *字典 和 **字典 参数之间,是否顺序可以随意

 

所以 *字典和普通参数之间,不需要考虑顺序和命明,但是需要注意位置参数x=1无论怎样都是放在最后的,如果放前面pycharm也会冒红报错。



例子5:
下面看 **字典 参数顺序,先看放最后面:

 

 在看放最前面:

 

看来 **字典 参数顺序是需要放在普通参数的后面。但是如果有位置参数,位置参数也还是一样放在最后面的。

例子6:
那么看看 *字典 和 **字典 的顺序。
先看看*字典在前面:

 

**字典在前面

 

所以*字典 和 **字典的顺序是 :*字典在前,**字典在后。

 

那么得出结论,各自之间的形参位置是:普通参数=*字典 ---> **字典 --> 位置参数。
而且当使用 **字典 解包后,函数的形参一定要和字典的键同名,否则解包失败。


 


 

外溢部分结束,接下来进入分类部分:------------------------------------------------

 

*args
  接收任意多个实际参数,并将其放到一个元组中
  使用已经存在的列表或元组作为函数的可变参数,可以在列表的名称前加*


例子1:

# *args 可以接受任意多个实际参数,并将其放到一个元祖当中
def print_language(*args):     # 定义一个函数,希望传进来的都可以被接收,用*args
    print(args)               # 函数体这里把接收到的参数打印出来,看看是什么
# 调用函数,把不同数量的函数传递进去,用位置参数
print_language("python", "java")                 # 调用函数,把不同的参数传递进去
print_language("python", "java", "php", "go")    # 第二次调用函数,把不同的参数传递进去

打印后

 

 打印后,前面传递进去的参数都被放在一个元祖中,想要把元祖中的参数拿出来分别做处理的话,可以给我们元祖做一个for循环。这样就可以每一个参数都做处理。见例子2.


例子2:

def print_language(*args):     
    print(args)               
    for i in args:         # 加了for循环,把元祖中的参数拿出来分别做处理。
        print(i)            
print_language("python", "java", "php", "go")    

打印后

 

 这样可以每一个参数拿出来做处理。


 例子3:想要通过已经存在的列表或者元祖来作为函数的可变参数的话也是可以的。

先看例子:

def print_language(*args):     
    print(args)              
    for i in args:
        print(i)
params = ["python", "java", "php", "go"]
print_language(params)         # 不带星*

打印

 

 这样是传递进去了,但是这整个列表它是作为了一个元素传递了进去。而我们希望列表当中的单个元素都能够当做一个参数传递进去。这是要注意,传参的时候在列表前面加上*号,加上去相当于做了一个
解包的操作。再来执行以下:

def print_language(*args):     
    print(args)              
    for i in args:
        print(i)
lan = ["python", "java", "php", "go"]       # 列表
print_language(*lan)        #  传参时候,列表前面加了*号,相当于解包的操作

打印:

这样就把列表中的每一个元素当做是一个参数传递进来。这些参数又被放到一个元祖当中,这就是调用的一个方式。
总结来看:参数定义的时候,星号*收集了所有的位置参数,并且把它放到一个元祖当中,arg就是一个元祖,这是一个打包的过程。在函数调用的过程当中,星号*可以把我们的列表、元祖把它解包成不同的参数传递进来。
其中:例子3这种方式=====例子2这种方式(两种方式是等价的结果)


 

 

**kwargs
接收任意多个类似关键字参数一样显式赋值的实际参数,并将其放到一个字典中
使用已经存在字典作为函数的可变参数,可以在字典的名称前加**


例子1:

def print_info(**kwargs):
    print(kwargs)
print_info(Tom=18, Jim=20)                # 调用函数
print_info(Tom=18, Jim=20, Lily=12)       # 调用函数

打印

 

调用两次,分别传入不同参数。这时打印出两个字典,关键字传参即:key=values的这种形式,都会被存放到一个字典当中去。同样的话,对传入进来的参数另外做处理的话。可以做一个循环,把里面的key或者values拿出来做对应的处理即可。
在定义函数的时候,两个**号实现了打包的过程,把key=values打包成一个字典。

 

 

同样的话,我们也可直接用一个字典来作为函数的一个可变参数的传入的值:

def print_info(**kwargs):
    print(kwargs)
params = {'Tom':18, 'Jim':20, 'Lily':12}
print_info(**params)

返回:

 

 


17:35:49

 

posted @ 2022-05-05 11:57  v_jjling  阅读(117)  评论(0编辑  收藏  举报
AmazingCounters.com