【Python语言基础】14、函数-04

文章目录

    • 1. 闭包
      • 1.1 基本概念
      • 1.2 闭包的作用
      • 1.3 注意事项
    • 2.装饰器引入
      • 2.1 基本概念
      • 2.2 带参数的装饰器
      • 2.3 带参数的装饰器函数
    • 3. 装饰器使用
      • 3.1 多个装饰器的使用
      • 3.2 类装饰器

1. 闭包

在 Python 里,闭包是一种特殊的函数,它能记住并访问其所在的封闭作用域中的变量,即便该封闭作用域已经执行完毕。将函数作为返回值返回,也是一种高阶函数,这种高阶函数称为闭包。通过创建闭包可以创建一些只有当前函数能访问的变量,可以将一些私有的数据藏到闭包中。

1.1 基本概念

闭包由以下几个部分构成:

  • 一个外部函数,它定义了一些局部变量。
  • 一个内部函数,它引用了外部函数的局部变量。
  • 外部函数返回内部函数。

一个简单的闭包示例

def fn() : 
    def inner () : 
        print('这是一个内部函数')
    return inner

# 接受结果
r = fn()
#调用
r()

# 结果:
这是一个内部函数

***Repl Closed***

def outer_function(x):
    def inner_function(y):
        return x + y
    return inner_function

closure = outer_function(10)
result = closure(5)
print(result)  

# 结果
15

***Repl Closed***

在这个例子中,outer_function 是外部函数,它接收一个参数 x。inner_function 是内部函数,它引用了外部函数的变量 x。outer_function 返回 inner_function。调用 outer_function(10) 会返回一个闭包,这个闭包记住了 x 的值为 10。之后调用这个闭包并传入参数 5,就会得到 10 + 5 的结果

1.2 闭包的作用

  • 数据封装和隐藏:
    闭包可以把数据封装在其内部,外部无法直接访问这些数据,只能通过闭包提供的接口来操作
def counter():
    count = 0
    def increment():
        nonlocal count
        count = count + 1
        return count
    return increment

c = counter()
print(c())  
print(c())  

在这个例子中,count 变量被封装在 counter 函数内部,外部无法直接访问它。只能通过调用闭包 c 来增加 count 的值。

  • 实现函数工厂
    闭包可以根据不用的参数生成不同的函数
def power_factory(n):
    def power(x):
        return x ** n
    return power

square = power_factory(2)
cube = power_factory(3)

print(square(5))  
print(cube(5))  

在这个例子中,power_factory 是一个函数工厂,它依据传入的参数 n 生成不同的幂函数

1.3 注意事项

  • nonlocal关键字:如果要在内部函数中修改外部函数的局部变量,需要使用nonlocal关键字
def outer():
    x = 10
    def inner():
        nonlocal x
        x = x + 1
        return x
    return inner

f = outer()
print(f())  
  • 内存占用:由于闭包会记住外部函数的局部变量,这些变量不会被垃圾回收机制回收,因此可能会占用较多的内存。在使用闭包时,需要注意避免内存泄露

2.装饰器引入

2.1 基本概念

装饰器本质上是一个函数,它接收一个函数作为参数,并且返回一个新的函数,如下

def my_decorator(func):
    def wrapper():
        print("在函数执行前做一些操作")
        func()
        print("在函数执行后做一些操作")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()

# 结果:
在函数执行前做一些操作
Hello!
在函数执行后做一些操作

***Repl Closed***

在这个例子中,my_decorator 就是一个装饰器,它接收 say_hello 函数作为参数,返回 wrapper 函数。使用 @my_decorator 语法糖可以将 say_hello 函数传递给 my_decorator

2.2 带参数的装饰器

如果被装饰的函数带有参数,装饰器需要能够处理这些参数。可以用过在wrapper函数中使用*args和**kwargs来实现

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("在函数执行前做一些操作")
        result = func(*args, **kwargs)
        print("在函数执行后做一些操作")
        return result
    return wrapper

@my_decorator
def add_numbers(a, b):
    return a + b

result = add_numbers(3, 5)
print(result)

# 结果
在函数执行前做一些操作
在函数执行后做一些操作
8

***Repl Closed***

2.3 带参数的装饰器函数

装饰器本身也可以的带有参数。这需要定义一个返回装饰器的函数:

def repeat(n):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(n):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def say_hi():
    print("Hi!")

say_hi()

# 结果:
Hi!
Hi!
Hi!

***Repl Closed***

在这个例子中,repeat 函数接收一个参数 n,并返回一个装饰器 decorator。

3. 装饰器使用

3.1 多个装饰器的使用

可以对一个函数应用多个装饰器:

def decorator1(func):
    def wrapper():
        print("装饰器1: 在函数执行前做一些操作")
        func()
        print("装饰器1: 在函数执行后做一些操作")
    return wrapper

def decorator2(func):
    def wrapper():
        print("装饰器2: 在函数执行前做一些操作")
        func()
        print("装饰器2: 在函数执行后做一些操作")
    return wrapper

@decorator1
@decorator2
def say_goodbye():
    print("Goodbye!")

say_goodbye()

# 结果:
装饰器1: 在函数执行前做一些操作
装饰器2: 在函数执行前做一些操作
Goodbye!
装饰器2: 在函数执行后做一些操作
装饰器1: 在函数执行后做一些操作

***Repl Closed***

装饰器的应用顺序是从下往上,也就是先应用 decorator2,再应用 decorator1。

3.2 类装饰器

除了函数装饰器,还可以使用类来实现装饰器

class MyDecorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print("在函数执行前做一些操作")
        result = self.func(*args, **kwargs)
        print("在函数执行后做一些操作")
        return result

@MyDecorator
def say_cheers():
    print("Cheers!")

say_cheers()

# 结果:
在函数执行前做一些操作
Cheers!
在函数执行后做一些操作

***Repl Closed***

在这个例子中,MyDecorator 类实现了 call 方法,使其实例可以像函数一样被调用

你可能感兴趣的:(Python,python,开发语言)