视频链接:

https://space.bilibili.com/70431433?spm_id_from=333.1007.0.0

文章代码链接:

https://github.com/zyf-ngu/Qmatter

4高阶函数

内部函数-闭包

在 Python 中,内部函数(嵌套函数)可以直接访问外部函数的参数和变量,这种特性称为闭包(Closure)。闭包允许内部函数捕获并记住外部函数的环境,即使外部函数已经执行完毕。

闭包类似 “实例化” 的效果 —— 创建多个独立的 “函数实例”,它们拥有各自独立的状态,互不干扰。通过 “局部状态记忆” 替代全局变量,将状态封装在函数内部,避免全局变量易引发命名冲突(如多个模块定义count变量)。

闭包的典型应用(记住外部环境)

def make_counter():

    count = 0  # 外部函数的变量

    

    def counter():

        nonlocal count

        count += 1

        return count

    

    # 返回内部函数(闭包)

    return counter

# 创建计数器实例

counter1 = make_counter()

counter2 = make_counter()

# 调用闭包,每个实例会记住自己的count状态

print(counter1())  # 1

print(counter1())  # 2

print(counter2())  # 1

print(counter1())  # 3

print(counter2())  # 2

关键规则:

  1. 读取外部参数 / 变量:内部函数可以直接读取外部函数的参数和变量。
  2. 修改限制:默认情况下,内部函数不能直接修改外部函数的不可变类型变量(如 int、str、tuple),但可以修改可变类型变量(如 list、dict)。

强制修改:如果需要修改外部函数的不可变变量,可以使用nonlocal关键字声明。

以下是关于 Python 嵌套函数(闭包)的具体实例,展示了不同情况下内部函数对外部变量的访问和修改方式:

实例 1:内部函数读取外部变量

def outer_function(message):

    # 外部函数的变量

    outer_var = "外部变量"

    

    def inner_function():

        # 内部函数读取外部变量和参数

        print(f"内部函数访问外部参数: {message}")

        print(f"内部函数访问外部变量: {outer_var}")

    

    # 调用内部函数,一般用于多线程处理

    inner_function()

# 调用外部函数

outer_function("外部参数")

输出:

内部函数访问外部参数: 外部参数

内部函数访问外部变量: 外部变量

实例 2:修改外部可变类型变量(list/dict)

def outer_function():

    # 外部函数的可变类型变量(列表)

    outer_list = [1, 2, 3]

    

    def inner_function():

        # 直接修改外部可变类型变量(无需特殊声明)

        outer_list.append(4)

        print(f"内部函数修改后的列表: {outer_list}")

    

    inner_function()

    return outer_list

# 调用外部函数

result = outer_function()

print(f"外部函数返回的列表: {result}")

输出:

内部函数修改后的列表: [1, 2, 3, 4]

外部函数返回的列表: [1, 2, 3, 4]

实例 3:修改外部不可变类型变量(需用 nonlocal)

def outer_function():

    # 外部函数的不可变类型变量(整数)

    outer_num = 10

    

    def inner_function():

        # 声明需要修改外部不可变变量

        nonlocal outer_num

        outer_num = 20  # 现在可以修改了

        print(f"内部函数修改后的数值: {outer_num}")

    

    inner_function()

    return outer_num

# 调用外部函数

result = outer_function()

print(f"外部函数返回的数值: {result}")

输出:

内部函数修改后的数值: 20

外部函数返回的数值: 20

装饰器函数

我们知道,函数是封装了特定功能的代码块,前面也介绍了函数参数的具体传递,不过参数均是简单的变量。如果我们想对函数的功能进行扩展应该怎么做呢?直接修改函数代码必然不是一个好选择,python提供了装饰器。

装饰器是Python中一个非常强大的功能,它允许我们修改或增强函数、方法或类的行为,而不需要改变其本身的代码。装饰器本质上是一个可调用对象(通常是一个函数),它接受一个函数作为参数,并返回一个新的函数。新函数包括2部分,核心部分是原函数的功能,第2部分就是新增的模式化的通用功能

其基本结构如下:

#1 定义一个接收函数为参数的装饰器函数

def decorator_function(func):

    #2定义一个包装函数(wrapper),参数使用*args,**kwargs,以适应各种参数的原函数,这里参数和原函数是对应的

def wrapper(*args,**kwargs):

    语句1  #3.在原函数前后增加一些通用的功能语句,也可以使用上面传递进来的参数

result=func(*args,**kwargs)#4.调用原函数

语句2

return result  #5原函数有返回值则返回值,包装函数结束

return wrapper   #最后返回扩展函数,装饰器函数结束

# 6 使用方式,@+装饰器函数名,下面跟着接收函数的定义,之后正常调用接收函数

@decorator_function

def func:

   pass

      

举个例子,在调用原函数前后添加了额外日志记录的功能。

def log_decorator(func):

def wrapper(*args, **kwargs):

for num in args:   #内部扩展函数的其它语句也可以使用
            print('num:',num)
        print(f"Before function {func.__name__} is called.")

result = func(*args, **kwargs)

print(f"After function {func.__name__} is called.")

return result

return wrapper

@log_decorator  # 接收函数为参数的函数名前面加@符号即为装饰器。

def add(a, b):   #原函数定义在下方

return a + b

result = add(3, 5)

print(result)

# 带参数的装饰器需要三层嵌套

def require_role(role):

    # 外层接收装饰器参数

    def decorator(original_func):

        # 中间层接收函数

        def wrapper(*args, **kwargs):

            # 内层实现装饰逻辑

            if role == "admin":

                print("管理员权限验证通过")

                return original_func(*args, **kwargs)

            else:

                raise PermissionError("权限不足!")

        return wrapper

    return decorator

# 应用带参数的装饰器

@require_role("admin")

def delete_database():

    print("数据库已删除!")

@require_role("user")

def view_data():

    print("显示数据...")

# 测试

delete_database()  # 成功执行

try:

view_data()     # 触发异常

except PermissionError as e:

    print(f"错误: {e}")

总结一下,装饰器函数本质上是一个函数,其主要功能和作用体现在以下几个方面:

1. 代码复用和模块化

装饰器可以将一些通用的功能(如日志记录、权限验证、性能测试等)封装起来,然后应用到多个不同的函数上,避免了代码的重复编写,提高了代码的复用性和可维护性。

2. 功能增强

在不修改原函数代码的前提下,为原函数添加额外的功能。这符合软件开发中的开闭原则,即对扩展开放,对修改关闭。

3. 分离关注点

将与核心业务逻辑无关的功能(如日志、权限控制等)从业务逻辑中分离出来,使代码结构更加清晰,便于维护和管理。

注意事项-

装饰器会改变被装饰函数的元信息(如函数名、文档字符串等),可以使用`functools.wraps`来保留这些信息。

- 装饰器在模块导入时就会执行,因此装饰器内部的代码会在导入时运行。

使用functools.wraps保留原始函数的元信息,

import functools

def my_decorator(func):

@functools.wraps(func)

def wrapper(*args, **kwargs):

print("装饰器中...")

return func(*args, **kwargs)

return wrapper

@my_decoratordef example():

 print("Hello")

print(example.__name__) # 输出 'example' 而不是 'wrapper'

print(example.__doc__) # 输出 '示例函数的文档字符串' 而不是 '包装函数的文档字符串'```

匿名函数(Lambda 函数)

匿名函数(Lambda 函数)是一种不需要使用 def 关键字定义的函数,它使用 lambda 关键字创建。Lambda 函数是一个小型、匿名的函数,可以接受任意数量的参数,但只能有一个表达式

语法:

func(可选,函数对象)=lambda arguments: expression

原理:
Lambda 函数在运行时创建返回一个函数对象。这个函数对象可以像普通函数一样被调用,参数在调用时传递进去,但它没有函数名(因此称为"匿名"函数)。

简洁性:对于简单的操作,使用 lambda 函数比定义完整函数更简洁

一次性使用:适用于只需要使用一次的小型函数

函数式编程:常与高阶函数(如 map(), filter(), reduce())配合使用

回调函数:作为参数传递给其他函数

# 1. lambda基本用法

add = lambda x, y: x + y

print(add(5, 3))  # 输出: 8

# 2. 与普通函数对比

def add_def(x, y):

    return x + y

# Lambda 版本更简洁

# 3. 在排序中使用

students = [("Alice", 90), ("Bob", 85), ("Charlie", 95)]# 按分数排序

sorted_students = sorted(students, key=lambda x: x[1])

print(sorted_students)  # 输出: [('Bob', 85), ('Alice', 90), ('Charlie', 95)]

# 4. 立即调用 lambda 函数

result = (lambda x, y: x * y)(5, 6)

print(result)  # 输出: 30

高阶函数

高阶函数是指能够接收函数作为参数或将函数作为返回值的函数。在 Python 中,函数是一等对象(first-class objects),这意味着函数可以像其他对象一样被传递和操作。通过将函数作为参数或返回值,实现了更高层次的抽象和代码复用。

抽象通用模式:将通用操作模式抽象出来,具体行为通过函数参数定制

代码复用:减少重复代码,提高代码的可维护性

函数组合:通过组合简单函数构建复杂功能

延迟执行:可以创建并返回函数,在需要时执行

高阶函数、闭包和装饰器之间的关系可以概括为:装饰器是闭包的一种应用,而闭包又是高阶函数的一种形式。

高阶函数是指能够接收函数作为参数,或者将函数作为返回值的函数。

闭包是指在一个内部函数中,对外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包。闭包允许函数记住并访问其词法作用域中的变量,即使函数是在其作用域之外执行。

装饰器本质上是一个函数,它接收一个函数作为参数,并返回一个新的函数。装饰器通常用于在不修改原函数代码的情况下,为函数添加新的功能。

装饰器是利用闭包和高阶函数的特性来实现的。

装饰器是一个高阶函数,因为它接收函数作为参数并返回函数。

装饰器内部通常会定义一个闭包(内部函数),这个闭包会引用外部函数的参数(即被装饰的函数)以及外部作用域的变量。

# 1. 接收函数作为参数的高阶函数lambda函数作为参数

def apply_operation(func, x, y):

    """应用给定的操作到两个参数上"""

    return func(x, y)

# 使用不同的操作

result1 = apply_operation(lambda a, b: a + b, 5, 3)

result2 = apply_operation(lambda a, b: a * b, 5, 3)

print(result1, result2)  # 输出: 8 15

# 2. Python 内置高阶函数

from functools import reduce

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

# map() - 对每个元素应用函数

squared = list(map(lambda x: x**2, numbers))

print(squared)  # 输出: [1, 4, 9, 16, 25]

# filter() - 过滤满足条件的元素

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

print(evens)  # 输出: [2, 4]

# reduce() - 累积计算序列中的元素

sum_all = reduce(lambda x, y: x + y, numbers)

print(sum_all)  # 输出: 15

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐