函数的进阶

参数的解包(拆包)

参数数据类型是:字符串|列表|元组|集合|字典的时候可以解包。

  • 传递参数时,可以在序列类型的参数前添加 * 这样会自动将序列中的元素一次作为参数传递;

拆包之后的实际参数个数必须和形式参数的个数保持一致,依次赋值,否则会报错!

s = "123"
l = [1, 2, 3]
t = (1, 2, 3)
s1 = {1, 2, 3}
d = {
    "name": "帅帅",
    "age": 21,
    "sex": ""
}
def fun(arg1, arg2, arg3):
    print("{} ~ {} ~ {}".format(arg1, arg2, arg3))

fun(*s)     # 1 ~ 2 ~ 3
fun(*l)     # 1 ~ 2 ~ 3
fun(*t)     # 1 ~ 2 ~ 3
fun(*s1)    # 1 ~ 2 ~ 3
fun(*d)     # name ~ age ~ sex 备注:只会打印字典的 key
# fun(**d)  # **d 可以输出字典的 value 但是前提要求:字典的key需要和函数的参数名保持一致

d = {
    "arg1": "帅帅",
    "arg2": 21,
    "arg3": ""
}
# **d 可以输出字典的 value 但是前提要求:字典的key需要和函数的参数名保持一致
fun(**d)    # 帅帅 ~ 21 ~ 男

参数解包和可变参数一起使用

注意:**参数只收集未匹配的关键字参数

# args 接受可变参数,元组类型
def fun(num, *args):
    print(num)
    print(args)
    print(type(args))   # <class 'tuple'>

fun(100, 200, 300, 400, 500)  # 输出 num = 100 args = (200, 300, 400, 500)
# 列表|元组|集合的解包
fun(100, *[200, 300, 400, 500]) # 输出 num = 100 args = (200, 300, 400, 500)
fun(100, *(200, 300, 400, 500)) # 输出 num = 100 args = (200, 300, 400, 500)
fun(100, *{200, 300, 400, 500}) # 输出 num = 100 args = (200, 300, 400, 500)

# **kwargs 接收关键字参数,字典类型
def fun(num, **kwargs):
    print(num)
    print(kwargs)
    print(type(kwargs)) # <class 'dict'>

fun(100, name="帅帅", age=21, sex="")    # 输出 100  kwargs = {'name': '帅帅', 'age': 21, 'sex': '男'}

d = {
    "name": "帅帅",
    "age": 21,
    "sex": ""
}
# 字典参数解包,配合普通参数一起使用
fun(100, **d)   # 输出 100 kwargs = {'name': '帅帅', 'age': 21, 'sex': '男'}

各种参数的排列顺序

函数中各种参数排列位置的注意事项:

  • 可变参数,必须定义在普通(位置)参数以及默认值参数的后面;
  • 函数定义时,二者同时存在,一定需要将 *args 放在 ** kwargs 之前 def fun(普通参数, 默认值参数 *参数, **参数): pass

顺序:位置参数 --> 默认值参数 --> *args 元祖类型可变参数 ---> **kwargs 字典类型可变参数

  • 默认参数 + 可变的元祖类型的参数,默认参数的默认值无效;【重点理解】若不传默认参数的值,会将可变参数 *args 的第一个值作为默认的参数值

默认参数 + 可变的字典类型的参数,默认参数的默认值生效!

def fun(num, name = "张三", *args, **kwargs):
    print(num)      # 100
    print(name)     # 帅帅
    print(args)     # (1, 2, 3, 4)
    for data in args:       # 可变参数元组的遍历
        print(data)
    print(kwargs)   # {'x': 10, 'y': 20, 'z': 30}
    for key, value in kwargs.items():   # 可变参数字典的遍历
        print(key, value)

fun(100, "帅帅", 1, 2, 3, 4, x = 10, y = 20, z = 30)

# 函数定义
def study(name, startTime, subject="c语言", *args, **kwargs):
    message = "{}学习{}的开始时间为:{}".format(name, subject, startTime)
    print(message)
    print("args = ", args)
    print("kwargs = ", kwargs)


lst = ["2023-10-01", "2023-10-10", "2023-11-10", "2024-02-17"]

studyMethod = {
    "c语言": "老师辅导",
    "mysql": "视频自学",
    "python": "书籍自学"
}

# 函数的调用:若不传默认参数的值,会将可变参数 *args 的第一个值作为默认的参数值
study("帅帅", "2023-09-20", "c语言", *lst, **studyMethod)

函数的return关键字

注意:函数可以使用 return 关键字返回数据,也可以不用 return 返回,此时函数执行完默认返回None

【1】函数执行完没有返回值

def fun(num1, num2):
    print("num1 = {}, num2 = {}".format(num1, num2))
    
fun(100, 200)   # num1 = 100, num2 = 200

【2】函数执行完只有一个返回值

def sum(num1, num2):
    return num1 + num2

result = sum(100, 200)
print("sum = %d" % result)      # sum = 300

【3】函数执行完有多个返回值(使用逗号分隔)

def swap(num1, num2):
    return num2, num1

# 推荐使用这种方式,明确每个返回值指定对应的接收变量
num1, num2 = swap(100, 200)
print("num1 =", num1, "num2 =", num2)   # num1 = 200 num2 = 100

# 另一种方式:使用元祖变量,接收多个返回值
t = swap(100, 200)
print(t)        # (200, 100)
print(type(t))  # <class 'tuple'>

num1, num2 = t  # 元组的解包,也可以这样来写 
print("num1 =", num1, "num2 =", num2)   # num1 = 200 num2 = 100

函数返回函数

  • 函数里面嵌套函数;
  • 函数返回函数;
def fun():
    def test():
        return [1, 2, 3]
    return test

# 接收函数类型的返回值
result = fun()
print(type(result)) # <class 'function'>
# 里层函数的调用
print(result())     # [1, 2, 3]
# 或者可以直接写
print(fun()())      # [1, 2, 3]

匿名函数lambda

"""
    lambda表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数。
    lambda就是用来定义一个匿名函数的,通常是直接使用lambda函数,不需要绑定一个名字!
    简洁大方,一般情况不通用,不对外提供!
    
    lambda 表达式:函数体一般情况下简洁明了,lambda 属于关键字,后面紧跟函数需要的参数
    语法: 函数名称 = lambda 参数 : 函数的函数体
    本质上就是一个函数的另外一种写法,意义:简单明了
"""
# 求解两个数的和
add = lambda x, y : (x+y)
print(add(1, 2))

# lambda函数应用在函数式编程中
lst = [-1, -3, -5, -7, -9, 2, 4, 6, 8, 10]
lst.sort(key=lambda x: abs(x))  # 按照绝对值进行升序排列
print(lst)

# 排序也可以这样来使用
lst2 = [-1, -3, -5, -7, -9, 2, 4, 6, 8, 10]
result = sorted(lst2, key=lambda x: abs(x))
print(result)

# 当然也可以这样来使用,先定义函数,然后传入函数参数即可
def numAbs(x):
    return abs(x)
lst3 = [-1, -3, -5, -7, -9, 2, 4, 6, 8, 10]
result = sorted(lst3, key=numAbs)
print(result)

函数的总结

"""
    1)函数的三大要素:返回值,函数名称,函数的参数
        函数的返回值,根据函数调用完成之后才确定,可以返回任意数据类型,根据实际的场景自行实现;
        函数名称:不能是关键字
        函数的参数:位置参数,默认参数,关键字参数;
            可变参数(元祖类型的可变参数 *args)(字典类型的可变参数 **kwargs)
        定义函数时,要使用关键字 def
    2)位置参数:【函数的定义方】
        位置参数接受的值可以是任意类型:数字(int float bool)字符串,元祖,列表,字典,集合
        位置参数需要和调用函数传递的参数一一对应,若缺少则报错(和C语言一样)
    3)默认参数:【函数的定义方】
        给函数的形式参数赋默认值;
        调用方若没有传默认参数的值,则取默认值,否则取传递的值
    4)关键字参数:【函数的调用方】
        例如:a = 1,b = 2,c = 3
        关键字参数的名称需要和函数的定义方形式参数的名称保持一致,若不一致则报错
    5)可变参数 *args:【函数的定义方】
        可变参数的类型为元祖的类型,不可变,使用 () 表示
    6)可变参数 **kwargs:【函数的定义方】
        可变参数的类型为字典的类型,可变,使用 {} 表示
        传递的参数形式:关键字参数的传递形式,但是需要注意:
            若传递关键字参数的名称和函数定义方的名称一致,就不会传递给可变参数 **kwargs,而且摆放是无序
    7)lambda 表达式:
        简单明了,一般情况下,函数体只有一行,本质上还是一个函数,另外一种写法而已
        语法:函数名称 = lambda 参数 : 函数的函数体

    注意:函数的定义方参数的顺序一般为:
        1位置参数 ---> 2默认参数 ---> 3可变参数 *args 元祖类型 ---> 4可变参数 **kwargs 字典类型
    若默认值参数 + 可变参数 *args 默认值参数无效(若不传默认值参数,可变参数的第一个值会默认传值);
    若默认值参数 + 可变参数 **kwargs 默认值参数生效(若不传默认值的参数,则取函数定义的默认值参数的值)
"""

 

posted @ 2024-03-26 11:31  帅帅的编程之路  阅读(4)  评论(0编辑  收藏  举报