【Python函数式编程】——闭包

简介: 一个函数定义中引入了函数定义以外的变量,并且该函数可以在其定义以外被执行,这样的一个函数称为闭包。

Python函数式编程——闭包

在这里插入图片描述

1.什么是闭包

  什么是闭包:一个函数定义中引入了函数定义以外的变量,并且该函数可以在其定义以外被执行,这样的一个函数称为闭包。

闭包的三个条件,缺一不可

"""
1)必须有一个内嵌函数(函数里定义的函数)——这对应函数之间的嵌套 

2)内嵌函数必须引用一个定义在闭合范围内(外部函数里)的变量——内部函数引用外部变量

3)外部函数必须返回内嵌函数——必须返回那个内部函数
"""

闭包代码实现:

# -*- coding: utf-8 -*-
# @File  : 闭包.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 15:58


# 定义一个函数
def fun_a(num_a):
    # 在函数内部再定义⼀个函数
    # 并且这个内部函数⽤到了外部的变量,这个函数以及⽤到外部函数的变量及参数叫 闭包
    def fun_b(num_b):
        print('内嵌函数fun_b的参数是:%s,外部函数fun_a的参数是:%s' % (num_b, num_a))
        return num_a + num_b
    # 这里返回的就是闭包的结果
    return fun_b


# 给fun_a函数赋值,这个10就是传参给fun_a
ret = fun_a(10)

# 注意这里的10其实是赋值给fun_b
print(ret(10))

# 注意这里的90其实是赋值给fun_b
print(ret(90))

在这里插入图片描述

  此时,内部函数对外部函数作⽤域⾥变量的引⽤(⾮全局变量),则称内部函数为闭包。

2.闭包修改外部变量

python交互环境idle

>>> def counter(start = 0):
    count = [start]
    def incr():
        count[0] += 1
        return count[0]
    return incr

>>> c1 = counter(5)
>>> print(c1())
6
>>> print(c1())
7
>>> print(c2())
51
>>> print(c2())
52
>>>
  当一个函数在本地作用域找不到变量申明时会向外层函数寻找,这在函数闭包中很常见但是在本地作用域中使用的变量后,还想对此变量进行更改就会报错。

看一段代码:

# -*- coding: utf-8 -*-
# @File  : 闭包修改外部变量.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 16:30


# 闭包修改外部变量的值
def test1():
    c = 1
    # c不是局部变量,是介于局部变量和全局变量之间的一种变量,用 nonlocal标识

    def add1():

        print(c)  # 1
        c += 1
        return c  # 2
    return add1


print(test1()())

报错信息:
在这里插入图片描述

此时,如果我在函数内加一行nonlocal c就可解决这个问题

代码:

# -*- coding: utf-8 -*-
# @File  : 闭包修改外部变量.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 16:30


# 闭包修改外部变量的值
def test1():
    c = 1
    # c不是局部变量,是介于局部变量和全局变量之间的一种变量,用 nonlocal标识

    def add1():
        nonlocal c
        print(c)  # 1
        c += 1
        return c  # 2
    return add1


print(test1()())

nonlocal声明的变量不是局部变量,也不是全局变量,而是外部嵌套函数内的变量(介于局部变量和全局变量之间的一种变量)。

使用 nonlocal的好处是,在为函数添加状态时不用额外地添加全局变量,因此可以大量地调用此函数并同时记录着多个函数状态,每个函数都是独立、独特的。

3.闭包的应用

闭包实现 y = a*x + b

# -*- coding: utf-8 -*-
# @File  : 闭包的应用.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 16:18


# y = a*x + b
def create_line(a, b):
    def line(x):
        return a * x + b

    return line


line1 = create_line(1, 1)  # a:1 b:1
line2 = create_line(4, 5)  # a:4 b:5

print(line1(5))  # 6
print(line2(5))  # 25
从这段代码中,函数 line与变量 a,b构成闭包。在创建闭包的时候,我们通过 create_line的参数 a,b说明了这两个变量的取值,这样,我们就确定了函数的最终形式( y = x + 1y = 4x + 5)。我们只需要变换参数 a,b,就可以获得不同的直线表达函数。

由此,我们可以看到,闭包也具有提⾼代码可复⽤性的作⽤。

如果没有闭包,我们需要每次创建函数的时候同时说明a,b,x。这样,我们就需要更多的参数传递,也减少了代码的可移植性。

1.闭包优化了变量,原来需要类对象完成的⼯作,闭包也可以完成
2.由于闭包引⽤了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存

4.闭包的陷阱

  函数内部函数,引用外部函数参数或值,进行内部函数运算执行,并不是完全返回一个函数,也有可能是一个在外部函数的值,我们还需要知道返回的函数不会立刻执行,而是直到调用了函数才会执行。

看代码:

# -*- coding: utf-8 -*-
# @File  : 闭包的陷阱.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 17:09


def fun_a():
    fun_list = []
    for i in range(1, 4):

        def fun_b():
            return i * i

        fun_list.append(fun_b)
    return fun_list


f1, f2, f3 = fun_a()
print(f1(), f2(), f3())  
# 9 9 9 
  这里创建了一个 fun_a函数,外部函数的参数 fun_list定义了一个列表,在进行遍历,循环函数 fun_b,引用外部变量i 计算返回结果,加入列表,每次循环,都创建了一个新的函数,然后,把创建的3个函数都返回了,但是实际结果并不是我们想要的 1, 4, 9,而是 999,这是为什么呢?

  这是因为,返回的函数引用了变量 i ,但不是立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,每一个独立的函数引用的对象是相同的变量,但是返回的值时候,3个函数都返回时,此时值已经完整了运算,并存储,当调用函数,产生值不会达成想要的,返回函数不要引用任何循环变量,或者将来会发生变化的变量,但是如果一定需要呢,如何修改这个函数呢?

我们fun_b()把这里的参数i赋值给x就可以解决

# -*- coding: utf-8 -*-
# @File  : 闭包的陷阱.py
# @author: Flyme awei 
# @email : Flymeawei@163.com
# @Time  : 2022/8/21 17:09


def fun_a():
    fun_list = []
    for i in range(1, 4):

        def fun_b(x=i):
            return x ** 2

        fun_list.append(fun_b)
    return fun_list


f1, f2, f3 = fun_a()
print(f1(), f2(), f3())  
# 1 4 9
  可以再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变,那我们就可以完成下面的代码:
# -*- coding: UTF-8 -*- # 
def fun_a(): 
    def fun_c(i): 
        def fun_b(): 
            return i * i 
            
        return fun_b 

    fun_list = [] 
    for i in range(1, 4): 
        # f(i)立刻被执行,因此i的当前值被传入f() 
        fun_list.append(fun_c(i)) 
    return fun_list 


f1, f2, f3 = fun_a() 
print(f1(), f2(), f3()) 
# 1 4 9

相关文章
|
17天前
|
Python
闭包(Closure)是**Python中的一种高级特性
闭包(Closure)是**Python中的一种高级特性
34 8
|
1月前
|
存储 缓存 算法
Python闭包|你应该知道的常见用例(下)
Python闭包|你应该知道的常见用例(下)
22 1
Python闭包|你应该知道的常见用例(下)
|
1月前
|
自然语言处理 小程序 测试技术
Python闭包|你应该知道的常见用例(上)
Python闭包|你应该知道的常见用例(上)
26 3
Python闭包|你应该知道的常见用例(上)
|
5月前
|
监控 测试技术 Python
颠覆传统!Python闭包与装饰器的高级实战技巧,让你的项目效率翻倍
【7月更文挑战第7天】Python的闭包与装饰器是强大的工具。闭包是能记住外部作用域变量的内部函数,常用于动态函数创建和工厂模式。例如,`make_power`返回含外部变量`n`的`power`闭包。装饰器则允许在不修改函数代码的情况下添加新功能,如日志或性能监控。`my_decorator`函数接收一个函数并返回包装后的函数,添加了前后处理逻辑。掌握这两者,可提升编程效率和灵活性。
43 3
|
2月前
|
存储 算法 数据处理
Python函数式编程
【10月更文挑战第12天】函数式编程是一种强大的编程范式,它可以帮助我们编写更加简洁、易读、可维护和高效的代码。虽然 Python 不是一种纯粹的函数式编程语言,但它提供了许多支持函数式编程的特性和功能。通过深入了解和掌握函数式编程的概念和技巧,我们可以在 Python 编程中更好地应用函数式编程的理念,提高我们的编程水平和代码质量。
21 2
|
3月前
|
Python
Python函数式编程-Filter
Python函数式编程-Filter
|
2月前
|
Python
深入理解Python中的闭包
深入理解Python中的闭包
30 0
|
4月前
|
Python
Python函数式编程:你真的懂了吗?理解核心概念,实践高阶技巧,这篇文章带你一次搞定!
【8月更文挑战第6天】本文介绍了Python中的函数式编程,探讨了高阶函数、纯函数、匿名函数、不可变数据结构及递归等核心概念。通过具体示例展示了如何利用`map()`和`filter()`等内置函数处理数据,解释了纯函数的一致性和可预测性特点,并演示了使用`lambda`创建简短函数的方法。此外,文章还强调了使用不可变数据结构的重要性,并通过递归函数实例说明了递归的基本原理。掌握这些技巧有助于编写更清晰、模块化的代码。
45 3
|
5月前
|
存储 分布式计算 索引
Python函数式编程入门窥探
Python本身不是一门函数式编程语言,但是它参考了一些函数式编程语言很好的地方,除了可以写出更可读的代码外。还能用它来实现一些特定功能,本身也提供了强大的注解系统和函数和对象之间的灵活调用。
|
4月前
|
数据安全/隐私保护 Python
Python闭包:函数定义的神秘力量!
Python闭包:函数定义的神秘力量!
60 0