您的位置:

Python闭包

一、什么是Python闭包

Python闭包是一个函数,它返回一个函数对象,并且可以访问外部函数的变量。通俗点说,闭包就是在一个函数中定义另一个函数,并且内部的函数可以获取外部函数的局部变量和参数,即使外部函数已经执行完毕。

具体来说,当一个函数嵌套在另一个函数中,并且内部函数引用外部函数的变量时,就形成了一个闭包。外部函数返回内部函数,内部函数可以访问外部函数的变量,这个内部函数就是闭包。


def outer(x):
    def inner(y):
        return x + y
    return inner
    
closure = outer(5)
print(closure(3))  # 输出8

在这个例子中,outer函数返回inner函数,inner函数可以访问outer函数的变量x,并且在调用closure时,传递了参数3,所以最终输出了8。

二、 Python闭包的作用

Python闭包有以下几个作用:

1. 保护数据

闭包可以保护外部函数的变量,使得外部函数的变量不会受到外界的干扰。


def outer():
    num = 0
    def inner():
        nonlocal num   # 使用非局部变量,让内部函数访问外部函数的变量
        num += 1
        return num
    return inner
    
closure = outer()
print(closure())   # 输出1
print(closure())   # 输出2

在这个例子中,内部函数对外部函数的变量进行了修改,但是这个变量不会被其他外界的变量干扰。使用nonlocal关键字,让内部函数访问外部函数的变量。

2. 延迟计算

闭包可以实现延迟计算,即只有在调用内部函数时才会进行计算。


def outer(x, y):
    def inner():
        return x + y
    return inner
    
closure = outer(2, 3)
print(closure())   # 输出5

在这个例子中,返回的闭包函数在调用时才会计算x + y,实现了延迟计算。

3. 实现装饰器

Python装饰器就是闭包的一个经典应用,它可以通过定义一个装饰器函数,来对其他函数进行扩展。


def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("Before calling the function.")
        result = func(*args, **kwargs)
        print("After calling the function.")
        return result
    return wrapper

@my_decorator
def my_function():
    print("Hello World!")

my_function()

在这个例子中,定义了一个装饰器函数my_decorator,这个装饰器函数接收一个函数作为参数,返回一个闭包函数wrapper,这个闭包函数在执行前后分别输出了Before calling the function.和After calling the function.。使用@my_decorator来装饰my_function,相当于把my_function作为参数传递给my_decorator函数,最终得到的就是一个新的my_function函数,并且在调用my_function时,会先调用wrapper函数。

三、Python闭包的注意事项

在使用Python闭包时,需要注意以下几个事项:

1. 避免使用可变对象作为外部函数的变量

在闭包中操作外部函数的变量时,如果使用了可变对象,可能会出现意料之外的结果。


def outer():
    nums = [1, 2, 3]
    def inner():
        nums.pop()
        return nums
    return inner
    
closure = outer()
print(closure())   # 输出[1, 2]
print(closure())   # 输出[1]
print(closure())   # 输出[]

在这个例子中,num是一个列表,每次调用inner函数时,都会修改这个列表,并且返回修改后的结果。但是由于列表是一个可变对象,所以每次调用inner函数时,返回的列表都是一样的,因为它们都是指向同一个列表。所以在使用闭包时,避免使用可变对象作为外部函数的变量。

2. 调用内部函数时,不需要传递参数

在调用闭包时,内部函数不需要传递参数,因为它已经获取了外部函数的变量。


def outer(x):
    def inner(y):
        return x + y
    return inner

closure = outer(5)
print(closure(3))   # 输出8
print(closure())    # 报错

在这个例子中,因为内部函数已经获取了外部函数的变量x,所以在调用closure时,只需要传递y这个参数。如果只调用inner(),不传递参数,就会报错。

3. 使用nonlocal关键字访问外部函数的变量

在内部函数中,如果想要设置外部函数的变量,必须使用nonlocal关键字来声明这个变量。


def outer():
    count = 0
    def inner():
        nonlocal count    # 使用nonlocal关键字,让内部函数访问外部的count变量
        count += 1
        return count
    return inner

closure = outer()
print(closure())   # 输出1
print(closure())   # 输出2

在这个例子中,内部函数inner对外部函数的变量count进行了修改,但是需要使用nonlocal关键字来声明一下这个变量,让内部函数访问外部函数的count变量。