第三章 · 函数

函数参数

本节目标

学完这一节,你会知道:

  1. 位置参数和关键字参数有什么区别
  2. 默认参数适合解决什么问题
  3. *args 如何接收任意数量的位置参数
  4. **kwargs 如何接收任意数量的关键字参数
  5. 如何用 *** 解包列表、元组和字典

这一节的重点不是炫技,而是让函数调用更灵活、更清楚。

先跑一个例子

新建文件 args_demo.py,写入:

def print_order(customer, *items, **info):
    print(f"顾客:{customer}")
    print(f"商品:{items}")
    print(f"其他信息:{info}")


print_order("小明", "苹果", "香蕉", address="成都", pay="微信")

运行:

python3 args_demo.py

你会看到:

顾客:小明
商品:('苹果', '香蕉')
其他信息:{'address': '成都', 'pay': '微信'}

*items 收集多个位置参数,**info 收集多个关键字参数。

位置参数和关键字参数

位置参数靠顺序传值:

def introduce(name, age, city):
    print(f"{name}{age}岁,来自{city}")


introduce("小明", 18, "成都")

关键字参数写出参数名:

introduce(name="小明", age=18, city="成都")

关键字参数的好处是顺序更灵活,也更容易读:

introduce(city="成都", name="小明", age=18)

默认参数

默认参数给参数一个默认值。

def greet(name, message="你好"):
    print(f"{message}{name}")


greet("小明")
greet("Alex", message="Hello")

输出:

你好,小明
Hello,Alex

注意:默认参数通常放在普通参数后面。

*args:接收多个位置参数

如果你不知道用户会传几个参数,可以用 *args

def sum_all(*args):
    total = 0
    for number in args:
        total += number
    return total


print(sum_all(1, 2))
print(sum_all(1, 2, 3, 4, 5))

输出:

3
15

args 本质上是一个元组:

def show_args(*args):
    print(type(args))
    print(args)


show_args("Python", 42, True)

**kwargs:接收多个关键字参数

**kwargs 接收任意数量的关键字参数。

def show_profile(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")


show_profile(name="小明", age=18, city="成都")

kwargs 本质上是一个字典。

一个更实际的例子:

def build_user(username, **profile):
    user = {"username": username}
    user.update(profile)
    return user


print(build_user("mage", city="成都", level=5))

参数顺序

如果一个函数里同时使用多种参数,常见顺序是:

def func(a, b, *args, c=10, **kwargs):
    pass

你可以先记住:

  1. 普通参数在前
  2. *args 在中间
  3. 带默认值的关键字参数在后
  4. **kwargs 放最后

刚入门时,不要把函数参数写得太复杂。

参数解包

解包就是把列表、元组、字典拆开传给函数。

解包列表和元组

def add(a, b, c):
    return a + b + c


numbers = [1, 2, 3]
print(add(*numbers))

add(*numbers) 等价于:

add(1, 2, 3)

元组也可以:

point = (10, 20, 30)
print(add(*point))

解包字典

def create_user(name, age, city):
    print(f"{name}{age}岁,来自{city}")


user = {"name": "小明", "age": 18, "city": "成都"}
create_user(**user)

create_user(**user) 等价于:

create_user(name="小明", age=18, city="成都")

逐行拆解

再看开头的例子:

def print_order(customer, *items, **info):

customer 是普通参数,*items 收集商品,**info 收集其他信息。

print_order("小明", "苹果", "香蕉", address="成都", pay="微信")

"小明" 传给 customer

"苹果""香蕉" 被收集到 items

address="成都"pay="微信" 被收集到 info

自己改一改

args_demo.py 改成日志函数:

def log(message, *tags, **metadata):
    print(f"消息:{message}")
    print(f"标签:{tags}")
    print(f"元数据:{metadata}")


log("用户登录", "auth", "info", user="admin", ip="127.0.0.1")

然后继续改:

  1. 如果没有标签,输出“无标签”
  2. " | ".join(tags) 把标签合并成一行
  3. 多调用几次,模拟不同日志

常见错误

1. 参数顺序写错

错误写法:

def greet(name="游客", age):
    print(name, age)

没有默认值的参数要放在有默认值的参数前面:

def greet(age, name="游客"):
    print(name, age)

2. 解包数量不匹配

def add(a, b, c):
    return a + b + c


numbers = [1, 2]
print(add(*numbers))

函数需要 3 个参数,但列表里只有 2 个值,会报 TypeError

3. 字典解包的键名对不上

def create_user(name, age):
    print(name, age)


data = {"username": "小明", "age": 18}
create_user(**data)

函数没有 username 参数,会报错。字典的键要和参数名一致。

4. 滥用 args 和 *kwargs

如果参数很明确,直接写清楚更好:

def register(name, age, city):
    pass

不要为了看起来高级,把所有函数都写成 *args, **kwargs

小练习

练习 1:求平均数

定义函数 average(*numbers),返回所有数字的平均值。

练习 2:打印用户资料

定义函数 print_profile(**info),逐行输出传入的资料。

练习 3:解包创建商品

定义函数 show_product(name, price, count),然后用字典解包调用它。

参考答案

练习 1:

def average(*numbers):
    return sum(numbers) / len(numbers)


print(average(80, 90, 100))

练习 2:

def print_profile(**info):
    for key, value in info.items():
        print(f"{key}: {value}")


print_profile(name="小明", city="成都", goal="学习 Python")

练习 3:

def show_product(name, price, count):
    print(f"{name} 单价 {price} 元,数量 {count}")


product = {"name": "苹果", "price": 3.5, "count": 4}
show_product(**product)

小结

这一节你学会了:

  1. 位置参数按顺序传值,关键字参数按名字传值
  2. 默认参数可以减少重复传参
  3. *args 会把多个位置参数打包成元组
  4. **kwargs 会把多个关键字参数打包成字典
  5. *** 可以把已有数据解包传给函数

下一节我们会学习lambda 与作用域,理解变量在函数内外是如何被查找的。

参数变灵活了,函数也更会接活了

*args 和 **kwargs 看起来像符号小怪兽,其实就是帮函数接住更多参数。先记住一个画面:args 是一串位置参数,kwargs 是一袋带名字的参数。多打印几次它们的内容,神秘感会很快散掉。

讨论 (0)

还没有评论,来抢沙发吧!