阅读指南:本文专为 Python 初中级工程师打造,从参数底层规则到装饰器高阶实战,再到 lambda 高效场景,全程代码可直接复制运行,覆盖 90% 面试高频考点与工程最佳实践,读完即可独立封装通用装饰器、写出优雅高阶代码。全文约 12000 字,建议收藏 + 关注,持续更新 Python 硬核干货!


前言:为什么函数进阶是 Python 核心分水岭

Python 是一门函数式 + 面向对象双范式语言,函数是一等公民。能否熟练驾驭参数、装饰器、匿名函数,直接决定代码优雅度、复用性与工程能力。

  • 初级工程师:只会基础 def、位置参数,代码冗余重复
  • 中级工程师:熟练 * args/**kwargs、lambda,简化逻辑
  • 高级工程师:自定义装饰器、闭包、高阶函数,实现无侵入增强

本文从基础→进阶→实战→面试四层拆解,保姆级教学,零基础也能吃透。


第一章 函数参数进阶:5 类参数 + 解包 + 避坑全解

1.1 函数参数核心规则与定义

函数参数分为形参(定义时)与实参(调用时),Python 支持 5 种参数类型,调用顺序严格约束:** 位置参数 → 默认参数 → *args → 关键字 - only 参数 → kwargs

1.2 位置参数:最基础也最严格

按定义顺序传递,数量必须完全匹配,缺一不可、多一报错。

python

运行

def add(x, y):
    """位置参数求和"""
    return x + y

print(add(10, 20))   # 正常:30
# print(add(10))     # 报错:缺少位置参数y
# print(add(10,20,30))# 报错:参数过多

工程要点:核心必传参数优先使用位置参数,保证调用清晰。

1.3 关键字参数:打破顺序限制

通过参数名指定值,顺序可任意调整,提升代码可读性。

python

运行

def person_info(name, age, city):
    return f"姓名:{name},年龄:{age},城市:{city}"

# 关键字参数调用,顺序无关
print(person_info(age=25, city="北京", name="张三"))

适用场景:参数较多时,避免因顺序错误导致 bug。

1.4 默认参数:简化调用,隐藏高频配置

定义时赋值,调用可传可不传,必须放在位置参数之后

python

运行

def power(base, exp=2):
    """幂运算,默认平方"""
    return base ** exp

print(power(3))    # 9(使用默认exp=2)
print(power(3, 3)) # 27(覆盖默认值)

⚠️ 致命坑:可变对象作为默认参数

绝对禁止用列表、字典、集合作为默认参数,会被全局复用,导致数据污染。

python

运行

# 错误写法
def append_item(item, lst=[]):
    lst.append(item)
    return lst

print(append_item(1))  # [1]
print(append_item(2))  # [1,2](预期[2],实际复用列表)

python

运行

# 正确写法:默认值设为None,内部初始化
def append_item(item, lst=None):
    if lst is None:
        lst = []
    lst.append(item)
    return lst

print(append_item(1))  # [1]
print(append_item(2))  # [2]

1.5 可变参数:*args 与 **kwargs,接收任意参数

1.5.1 *args:接收任意位置参数,打包为元组

python

运行

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

print(sum_all(1,2,3,4,5))  # 15
print(sum_all(10,20))       # 30

1.5.2 **kwargs:接收任意关键字参数,打包为字典

python

运行

def print_info(**kwargs):
    for k, v in kwargs.items():
        print(f"{k}: {v}")

print_info(name="李四", age=28, job="工程师")

1.5.3 混合使用:完整参数顺序

python

运行

def func(a, b=2, *args, c, **kwargs):
    print(a, b, args, c, kwargs)

func(1, 3, 4, 5, c=6, d=7, e=8)
# 输出:1 3 (4, 5) 6 {'d':7, 'e':8}

1.6 参数解包:*,一键展开容器

调用函数时,用 * 解包列表 / 元组,** 解包字典,简化传参。

python

运行

# 列表解包
nums = [10, 20]
print(add(*nums))  # 等价add(10,20)

# 字典解包
info = {"name":"王五", "age":30}
print(person_info(**info, city="上海"))

1.7 关键字 - only 参数:强制命名传递

在 * args 后定义参数,必须用关键字传递,避免歧义。

python

运行

def func(a, *args, b, c=0):
    print(a, args, b, c)

func(1, 2, 3, b=4)  # 正确
# func(1,2,3,4)     # 报错:b缺失关键字

1.8 参数进阶总结

  1. 顺序:位置→默认→*args→关键字 - only→**kwargs
  2. 默认参数禁用可变对象
  3. *args 收位置,**kwargs 收关键字
  4. 解包简化批量传参
  5. 关键字 - only 参数提升调用安全性

第二章 匿名函数 lambda:一行代码的优雅神器

2.1 什么是 lambda?

lambda 是单行匿名函数,无需 def 定义,无函数名,适用于简单一次性逻辑。语法lambda 参数1,参数2...: 表达式

  • 只能有一行表达式,自动返回结果
  • 无 if 多分支、无循环、无赋值语句
  • 用完即销毁,不占用命名空间

2.2 基础用法

python

运行

# 定义加法lambda
add_lambda = lambda x, y: x + y
print(add_lambda(5, 6))  # 11

# 平方运算
square = lambda x: x ** 2
print(square(4))  # 16

2.3 核心场景:配合高阶函数

lambda90% 用于 map/filter/sorted/sort 等高阶函数,简化代码。

2.3.1 sorted/sort 自定义排序

python

运行

# 按列表中元组第二个元素升序
lst = [("apple", 5), ("banana", 2), ("orange", 8)]
lst.sort(key=lambda x: x[1])
print(lst)  # [('banana',2), ('apple',5), ('orange',8)]

# 按字符串长度降序
str_lst = ["python", "java", "c", "javascript"]
new_lst = sorted(str_lst, key=lambda x: len(x), reverse=True)

2.3.2 map 映射转换

python

运行

# 列表元素乘2
num_lst = [1,2,3,4,5]
res = list(map(lambda x: x*2, num_lst))
print(res)  # [2,4,6,8,10]

2.3.3 filter 条件过滤

python

运行

# 筛选偶数
res = list(filter(lambda x: x % 2 == 0, num_lst))
print(res)  # [2,4]

2.3.4 max/min 自定义比较

python

运行

# 找字典中年龄最大的人
people = [{"name":"A","age":20}, {"name":"B","age":25}]
max_age = max(people, key=lambda x: x["age"])

2.4 lambda 高级用法

2.4.1 三元表达式结合 lambda

python

运行

compare = lambda x, y: x if x > y else y
print(compare(10, 20))  # 20

2.4.2 闭包中使用 lambda

python

运行

def outer(n):
    return lambda x: x * n

double = outer(2)
print(double(5))  # 10

2.5 lambda 使用禁忌

  1. 禁止复杂逻辑:超过一行请用 def 函数
  2. 禁止嵌套多层 lambda,可读性极差
  3. 禁止在全局作用域大量定义 lambda
  4. 禁止赋值复杂表达式,违背简洁初衷

2.6 lambda vs 普通函数

表格

特性 lambda 普通函数 def
命名 匿名 有明确函数名
行数 仅限一行 任意行数
逻辑 简单表达式 复杂逻辑、分支、循环
复用 一次性使用 多次复用
调试 难以调试 支持文档字符串、断点

第三章 装饰器:Python 最优雅的语法糖,无侵入增强函数

3.1 装饰器核心认知

装饰器 =闭包 + 高阶函数 +@语法糖,在不修改原函数代码与调用方式的前提下,为函数添加额外功能。典型场景:日志打印、执行计时、权限校验、参数校验、缓存、重试、事务管理。

3.2 前置知识:闭包与函数一等对象

3.2.1 函数一等对象

  • 可作为参数传递
  • 可作为返回值返回
  • 可赋值给变量
  • 可存储在容器中

3.2.2 闭包:记住外层作用域变量

嵌套函数引用外层非全局变量,外层函数执行完毕后,变量仍被保留。

python

运行

def counter():
    count = 0
    def inner():
        nonlocal count
        count += 1
        return count
    return inner

c = counter()
print(c())  # 1
print(c())  # 2

3.3 最简装饰器:入门案例

python

运行

def simple_decorator(func):
    def wrapper():
        print("函数执行前")
        func()
        print("函数执行后")
    return wrapper

@simple_decorator  # 等价 say = simple_decorator(say)
def say():
    print("Hello Python")

say()

输出:函数执行前Hello Python函数执行后

3.4 通用装饰器:支持任意参数与返回值

使用 * args/**kwargs 适配所有函数,保留原函数返回值。

python

运行

def通用装饰器(func):
    def wrapper(*args, **kwargs):
        # 前置操作
        print(f"调用函数:{func.__name__}")
        # 执行原函数
        result = func(*args, **kwargs)
        # 后置操作
        print(f"函数执行完毕,返回值:{result}")
        return result
    return wrapper

@通用装饰器
def add(a, b):
    return a + b

print(add(3, 4))

3.5 保留原函数元信息:functools.wraps

装饰后原函数__name__/__doc__会被 wrapper 覆盖,用 wraps 修复。

python

运行

import functools

def timer(func):
    @functools.wraps(func)  # 保留原函数信息
    def wrapper(*args, **kwargs):
        import time
        start = time.time()
        res = func(*args, **kwargs)
        print(f"耗时:{time.time()-start:.4f}s")
        return res
    return wrapper

@timer
def test():
    """测试函数"""
    return "ok"

print(test.__name__)  # test(未修复则为wrapper)
print(test.__doc__)   # 测试函数

3.6 带参数的装饰器:三层嵌套

外层接收装饰器参数,中间接收函数,内层包装执行。

python

运行

def log_level(level="INFO"):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print(f"[{level}] 执行函数:{func.__name__}")
            return func(*args, **kwargs)
        return wrapper
    return decorator

@log_level(level="ERROR")
def error_func():
    print("出错了")

error_func()

3.7 类装饰器:基于__call__实现

通过类实现装饰器,适合状态保存与复杂逻辑。

python

运行

class Retry:
    def __init__(self, max_retry=3):
        self.max_retry = max_retry

    def __call__(self, func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            for i in range(self.max_retry):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    print(f"第{i+1}次重试,异常:{e}")
            raise Exception("重试失败")
        return wrapper

@Retry(max_retry=2)
def test_err():
    raise ValueError("测试异常")

test_err()

3.8 装饰器堆叠:多个装饰器顺序执行

多个 @装饰器,执行顺序从下到上,调用顺序从上到下。

python

运行

@decorator1
@decorator2
def func():
    pass
# 等价:decorator1(decorator2(func))

3.9 工程级装饰器实战

3.9.1 计时装饰器(通用)

python

运行

import time, functools
def timer(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        t_start = time.perf_counter()
        res = func(*args, **kwargs)
        t_cost = time.perf_counter() - t_start
        print(f"{func.__name__} 耗时:{t_cost:.6f}s")
        return res
    return wrapper

3.9.2 参数类型校验装饰器

python

运行

def type_check(*types):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            for arg, typ in zip(args, types):
                if not isinstance(arg, typ):
                    raise TypeError(f"参数类型错误,期望{typ}")
            return func(*args, **kwargs)
        return wrapper
    return decorator

@type_check(int, int)
def add(a, b):
    return a + b

3.9.3 缓存装饰器(lru_cache 原理)

python

运行

def cache_decorator(func):
    cache = {}
    @functools.wraps(func)
    def wrapper(*args):
        if args in cache:
            return cache[args]
        res = func(*args)
        cache[args] = res
        return res
    return wrapper

@cache_decorator
def fib(n):
    if n <= 1:
        return n
    return fib(n-1) + fib(n-2)

3.10 装饰器总结

  1. 本质:高阶函数 + 闭包,无侵入增强函数
  2. 通用模板:wrapper+*args/**kwargs + 返回值
  3. 必须用 functools.wraps 保留元信息
  4. 带参数装饰器:三层嵌套
  5. 类装饰器:适合状态管理
  6. 工程常用:计时、日志、校验、缓存、重试

第四章 综合实战:参数 + lambda + 装饰器联动案例

4.1 数据处理流水线

python

运行

@timer
def data_process(data_list, *filters, **kwargs):
    # 过滤:lambda+filter
    for f in filters:
        data_list = list(filter(f, data_list))
    # 映射:lambda+map
    mapper = kwargs.get("mapper", lambda x: x)
    data_list = list(map(mapper, data_list))
    return sum(data_list)

# 调用:筛选>5,乘2,求和
res = data_process([1,3,6,8,10], lambda x: x>5, mapper=lambda x: x*2)
print(res)

4.2 接口请求加固装饰器

python

运行

@log_level("INFO")
@timer
@Retry(max_retry=3)
def request_api(url):
    import requests
    return requests.get(url).status_code

request_api("https://www.baidu.com")

第五章 高频面试真题(必背)

  1. Python 参数传递顺序是什么?
  2. 默认参数为什么不能用列表?如何修复?
  3. *args 与 **kwargs 区别与使用场景?
  4. lambda 限制有哪些?适用场景?
  5. 装饰器原理是什么?functools.wraps 作用?
  6. 手写计时装饰器、带参数日志装饰器
  7. 闭包与装饰器关系?
  8. 装饰器堆叠执行顺序?
  9. 类装饰器实现原理?
  10. 如何用装饰器实现函数缓存?

第六章 学习路线与进阶建议

  1. 先吃透参数规则,避免工程 bug
  2. lambda 只用于简单场景,复杂逻辑用 def
  3. 装饰器从通用模板开始,逐步实现业务需求
  4. 多看开源框架源码:Flask/Django/Requests 大量使用装饰器
  5. 封装自己的装饰器库,提升开发效率

结语

函数进阶是 Python 从入门到精通的必经之路,参数保证灵活调用,lambda 简化简洁逻辑,装饰器实现优雅增强。本文覆盖所有核心知识点与工程实战,建议反复练习,把代码敲熟。

原创不易,点赞 + 收藏 + 关注,后续将更新《Python 闭包与装饰器源码解析》《高阶函数实战 100 例》,带你彻底吃透 Python 函数式编程!

更多推荐