欢迎访问宙启技术站
智能推送

Python函数闭包的概念和运用

发布时间:2023-06-15 10:00:13

Python函数闭包是一种特殊的函数,它可以捕获其定义时的环境变量,并且可以在之后的调用中使用这些变量。换句话说,闭包是在函数内部定义的函数,它可以引用在外部函数中定义的变量。

使用闭包可以实现很多有用的功能,比如缓存数据、封装私有变量、延迟执行等。下面将从如何定义闭包、闭包的作用以及实际应用三个方面介绍Python函数闭包。

1、如何定义闭包?

要定义闭包,我们先来了解一下嵌套函数。嵌套函数是指在一个函数内部定义了另一个函数。例如:

def outer_func():
    x = 10
    
    def inner_func():
        print(x)
    
    inner_func()

在上面的代码中,我们在outer_func()函数内部定义了一个inner_func()函数,inner_func()函数可以访问outer_func()函数内部的变量(x)。

要将inner_func()函数变为闭包,我们需要在内部函数引用外部函数定义的变量,然后将内部函数返回。例如:

def outer_func():
    x = 10
    
    def inner_func():
        print(x)
    
    return inner_func

my_func = outer_func()
my_func()

在上面的代码中,outer_func()函数返回内部函数inner_func(),my_func变量指向了inner_func()函数。我们可以通过my_func()调用inner_func()函数,这样我们就得到了一个使用闭包的函数。

2、闭包的作用

闭包的作用非常广泛,下面我们来看看闭包的几个常见用途:

(1)缓存数据

闭包可以用来缓存函数的结果,避免重复计算。例如:

def memoize(func):
    cache = {}
    
    def inner_func(n):
        if n in cache:
            return cache[n]
        else:
            result = func(n)
            cache[n] = result
            return result
    
    return inner_func

@memoize
def fibonacci(n):
    if n in (0, 1):
        return n
    else:
        return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(10))

在上面的代码中,我们定义了一个memoize()函数,它接收一个函数作为参数,并返回一个闭包inner_func()。inner_func()函数用来缓存函数的结果,如果输入的参数n已经计算过了,就直接返回结果,否则计算结果并将结果缓存到字典cache中。

我们使用@memoize装饰器将fibonacci()函数传递给memoize()函数,这样每次调用fibonacci()函数时都会使用内部的缓存机制,避免重复计算。当我们运行fibonacci(10)时,程序会先计算fibonacci(0)、fibonacci(1)、fibonacci(2)……直到计算出fibonacci(10),然后将这些结果缓存起来,以便下次使用。

(2)封装私有变量

在Python中,使用闭包可以实现类似于私有变量的效果。例如:

def counter():
    count = [0]
    
    def inc():
        count[0] += 1
        return count[0]
    
    return inc

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

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

在上面的代码中,我们定义了一个counter()函数,它返回了一个内部函数inc(),外部无法直接访问count变量,只能通过调用inc()函数来间接修改count变量。当我们运行c1()函数时,程序会将count变量自增1,并返回自增后的值,第一次调用c1()会返回1,第二次调用会返回2。当我们再次调用counter()函数,会返回一个新的闭包,它使用了新的count变量,并从1开始计数。

(3)延迟执行

闭包可以用来实现延迟执行,也就是在稍后的时间调用函数。例如:

def delay(fn, *args, **kwargs):
    def inner_func():
        return fn(*args, **kwargs)
    
    return inner_func

def greet(name):
    print(f"Hello, {name}!")

delayed_greet = delay(greet, "Jack")
delayed_greet()

在上面的代码中,我们定义了一个delay()函数,它接收一个函数以及它的参数,并返回一个闭包inner_func()。当我们调用delayed_greet()函数时,程序会调用inner_func()函数,类似于上下文管理器一样,这样我们就可以在稍后的时间调用greet()函数。

3、实际应用

Python函数闭包可以用来实现很多实际应用,这里介绍一些常见的应用:

(1)装饰器

装饰器是一种特殊的闭包,它用来增强函数的功能。例如:

def my_decorator(func):
    def wrapper():
        print("Before function...")
        func()
        print("After function...")
    
    return wrapper

@my_decorator
def hello():
    print("Hello, World!")

hello()

在上面的代码中,我们定义了一个my_decorator()函数,并用@my_decorator装饰hello()函数,这样每次调用hello()函数时,都会先输出“Before function...”,然后调用hello()函数本身,最后输出“After function...”。

(2)状态机

状态机是一种有限状态自动机,它可以根据当前状态和输入事件转移到下一个状态。闭包可以用来实现状态机的逻辑。例如:

def state_machine():
    state = "start"
    
    def start_func():
        nonlocal state
        print("Start...")
        state = "running"
    
    def running_func():
        nonlocal state
        print("Running...")
        state = "stop"
    
    def stop_func():
        nonlocal state
        print("Stop...")
        state = "start"
    
    while True:
        if state == "start":
            start_func()
        elif state == "running":
            running_func()
        elif state == "stop":
            stop_func()

state_machine()

在上面的代码中,我们定义了一个state_machine()函数,它包含了三个内部函数(start_func、running_func、stop_func),这三个函数分别表示状态机的三个状态(开始、运行、停止)。状态机通过不断循环,根据当前状态调用对应状态的函数,实现状态转移的逻辑。

(3)生成器

生成器是一种特殊的函数,它可以在运行时生成一系列值。闭包可以用来实现简单的生成器。例如:

def countdown(n):
    def inner_func():
        nonlocal n
        n -= 1
        return n

    return inner_func

c = countdown(5)
for i in range(5):
    print(c())

在上面的代码中,我们定义了一个countdown()函数,它返回一个闭包inner_func(),每次运行inner_func()函数时,n减去1并返回n。这样我们就实现了一个简单的生成器,输出从5到1的数字。