函数参数
本节目标
学完这一节,你会知道:
- 位置参数和关键字参数有什么区别
- 默认参数适合解决什么问题
*args如何接收任意数量的位置参数**kwargs如何接收任意数量的关键字参数- 如何用
*和**解包列表、元组和字典
这一节的重点不是炫技,而是让函数调用更灵活、更清楚。
先跑一个例子
新建文件 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
你可以先记住:
- 普通参数在前
*args在中间- 带默认值的关键字参数在后
**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")
然后继续改:
- 如果没有标签,输出“无标签”
- 用
" | ".join(tags)把标签合并成一行 - 多调用几次,模拟不同日志
常见错误
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)
小结
这一节你学会了:
- 位置参数按顺序传值,关键字参数按名字传值
- 默认参数可以减少重复传参
*args会把多个位置参数打包成元组**kwargs会把多个关键字参数打包成字典*和**可以把已有数据解包传给函数
下一节我们会学习lambda 与作用域,理解变量在函数内外是如何被查找的。
参数变灵活了,函数也更会接活了
*args 和 **kwargs 看起来像符号小怪兽,其实就是帮函数接住更多参数。先记住一个画面:args 是一串位置参数,kwargs 是一袋带名字的参数。多打印几次它们的内容,神秘感会很快散掉。
还没有评论,来抢沙发吧!