Python函数进阶:*args和**kwargs、lambda匿名函数,让代码瞬间简洁

上一篇文章讲了函数基础,这篇文章讲函数的三个进阶特性:*args、**kwargs、lambda。学会这三个,你的代码会简洁很多。


一句话概括

这篇文章解决一个问题:**掌握 *args、kwargs 和 lambda 的用法,让函数更灵活。


*args:接收任意数量的位置参数

有时候我们不知道函数会有多少个参数,*args 解决了这个问题。

def sum_all(*args):
    """求所有参数的和"""
    total = 0
    for num in args:
        total += num
    return total

print(sum_all(1, 2, 3))        # 6
print(sum_all(1, 2, 3, 4, 5)) # 15
print(sum_all())              # 0(没有参数)

args 是一个元组,包含了所有传入的位置参数。


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

类似地,**kwargs 接收任意数量的关键字参数。

def print_info(**kwargs):
    """打印所有关键字参数"""
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_info(name="小明", age=18, city="北京")
# 输出:
# name: 小明
# age: 18
# city: 北京

kwargs 是一个字典


组合使用 *args 和 **kwargs

def func(*args, **kwargs):
    print(f"位置参数:{args}")
    print(f"关键字参数:{kwargs}")

func(1, 2, 3, name="小明", age=18)
# 输出:
# 位置参数:(1, 2, 3)
# 关键字参数:{'name': '小明', 'age': 18}

实战:用 *args 和 **kwargs 简化代码

练习1:动态格式化

def create_message(template, *args, **kwargs):
    """模板消息"""
    # 用传入的参数替换模板中的占位符
    message = template.format(*args, **kwargs)
    return message

msg = create_message(
    "您好,{name}!您的订单{order_id}已发货,预计{day}天后送达。",
    name="张三",
    order_id="ORD12345",
    day="3"
)
print(msg)
# 您好,张三!您的订单ORD12345已发货,预计3天后送达。

练习2:日志记录器

def log(level, *args, **kwargs):
    """简化版日志记录"""
    # 如果传了 time 参数就用,否则用当前时间
    time = kwargs.pop("time", None)
    
    if time:
        print(f"[{level}] {time}: {' '.join(str(a) for a in args)}")
    else:
        print(f"[{level}] {' '.join(str(a) for a in args)}")

log("INFO", "服务器启动")
log("ERROR", "连接失败", "重试次数:", 3)
log("DEBUG", "用户登录", "user_id:", 12345, time="10:30:00")

lambda:匿名函数

有时候需要一个简单的函数,但懒得写 def ...,这时候用 lambda。

lambda 的基本语法

# 普通函数
def add(x, y):
    return x + y

# lambda版本
add = lambda x, y: x + y

# 调用
print(add(10, 20))  # 30

lambda 参数: 返回值


lambda 适合的场景

1. 作为参数传给其他函数

# 按名字排序
names = ["Charlie", "Alice", "Bob"]
sorted_names = sorted(names, key=lambda x: x.lower())
print(sorted_names)  # ['Alice', 'Bob', 'Charlie']

# 按成绩排序
students = [("小明", 85), ("小红", 92), ("小李", 78)]
sorted_students = sorted(students, key=lambda x: x[1], reverse=True)
print(sorted_students)  # [('小红', 92), ('小明', 85), ('小李', 78)]

# map:对每个元素做操作
numbers = [1, 2, 3, 4, 5]
squares = list(map(lambda x: x ** 2, numbers))
print(squares)  # [1, 4, 9, 16, 25]

# filter:过滤元素
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens)  # [2, 4]

2. 简化返回函数的函数

# 普通写法
def make_multiplier(n):
    def multiplier(x):
        return x * n
    return multiplier

# 用lambda简化
make_multiplier = lambda n: lambda x: x * n

double = make_multiplier(2)
triple = make_multiplier(3)

print(double(5))   # 10
print(triple(5))   # 15

列表排序:key 参数详解

sorted()list.sort()key 参数非常有用:

# 按字符串长度排序
words = ["Python", "is", "great"]
sorted_words = sorted(words, key=len)
print(sorted_words)  # ['is', 'great', 'Python']

# 按字典的某个字段排序
students = [
    {"name": "小明", "score": 85},
    {"name": "小红", "score": 92},
    {"name": "小李", "score": 78},
]

sorted_students = sorted(students, key=lambda x: x["score"], reverse=True)
for s in sorted_students:
    print(f"{s['name']}: {s['score']}")

map/filter/reduce

这是函数式编程的三个核心函数:

map:对每个元素做操作

# 不用map
numbers = [1, 2, 3, 4, 5]
squares = []
for n in numbers:
    squares.append(n ** 2)

# 用map
squares = list(map(lambda x: x ** 2, numbers))

# 等价的列表推导式
squares = [x ** 2 for x in numbers]

filter:过滤元素

# 不用filter
numbers = [1, 2, 3, 4, 5]
evens = []
for n in numbers:
    if n % 2 == 0:
        evens.append(n)

# 用filter
evens = list(filter(lambda x: x % 2 == 0, numbers))

# 等价的列表推导式
evens = [x for x in numbers if x % 2 == 0]

reduce:汇总所有元素

from functools import reduce

numbers = [1, 2, 3, 4, 5]

# 不用reduce
product = 1
for n in numbers:
    product *= n

# 用reduce
product = reduce(lambda x, y: x * y, numbers, 1)  # 1是初始值
print(product)  # 120

常见问题FAQ

Q1:什么时候用 lambda?

  • 函数很简单,只用一次
  • 作为参数传给另一个函数(sorted、map、filter等)
  • 想让代码更简洁

如果函数逻辑复杂(超过一行),建议用 def


Q2:*args 和 **kwargs 可以同时用吗?

可以,但*args必须在**kwargs前面

def func(*args, **kwargs):
    pass

Q3:lambda 能访问外部变量吗?

可以,这叫闭包

make_adder = lambda x: lambda y: x + y
add5 = make_adder(5)
print(add5(10))  # 15

写在最后

这篇文章覆盖了函数的三个进阶特性:

  • *args:接收任意数量的位置参数(元组)
  • **kwargs:接收任意数量的关键字参数(字典)
  • lambda:匿名函数,简洁定义简单函数

下一篇文章:Python 文件读写,读取TXT和CSV、处理异常。


参考资料

更多推荐