python基础2——闭包函数

本文详细解析了Python中闭包的概念、特点及其实现方式,包括闭包如何引用外部函数的变量,闭包函数的必要条件,以及如何通过闭包提高代码的可复用性。同时,文章还提供了一个使用闭包进行日志记录的实用案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、闭包的概念

简而言之, 闭包的特点就是内部函数引用了外部函数中的变量。

简单粗暴地理解为闭包就是一个定义在函数内部的函数,闭包使得变量即使脱离了该函数的作用域范围也依然能被访问到。

二、闭包函数的必要条件:

1、闭包函数必须返回一个函数对象
2、闭包函数返回的那个函数必须引用外部变量(一般不能是全局变量),而返回的那个函数内部不一定要return

一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。
但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。

def line_conf(a, b):
    def line(x):
        return a*x + b
    return line
 
line1 = line_conf(1, 1)
line2 = line_conf(4, 5)
print(line1(5))
print(line2(5))

这个例子中,函数line与变量a,b构成闭包。在创建闭包的时候,我们通过line_conf的参数a,b说明了这两个变量的取值,这样,我们就确定了函数的最终形式(y = x + 1和y = 4x + 5)。我们只需要变换参数a,b,就可以获得不同的直线表达函数。
由此,我们可以看到,闭包也具有提高代码可复用性的作用。

三、闭包函数的判断

函数名.closure 在函数是闭包函数时,返回一个cell元素;不是闭包时,返回None。
输出cell:

def func():
    name = 'python'
    def inner():
        print(name)
    print(inner.__closure__) 
    return inner

f = func()
f()

输出None:

name = 'python'
def func():
    def inner():
        print(name)
    print(inner.__closure__)  # None
    return inner

f = func()
f()

4、闭包实现快速给不同项目记录日志

实例

    import logging
    def log_header(logger_name):
        logging.basicConfig(level=logging.DEBUG, format='%(asctime)s [%(name)s] %(levelname)s  %(message)s',
                            datefmt='%Y-%m-%d %H:%M:%S')
        logger = logging.getLogger(logger_name)
 
        def _logging(something,level):
            if level == 'debug':
                logger.debug(something)
            elif level == 'warning':
                logger.warning(something)
            elif level == 'error':
                logger.error(something)
            else:
                raise Exception("I dont know what you want to do?" )
        return _logging
 
    project_1_logging = log_header('project_1')
 
    project_2_logging = log_header('project_2')
 
    def project_1():
 
        #do something
        project_1_logging('this is a debug info','debug')
        #do something
        project_1_logging('this is a warning info','warning')
        # do something
        project_1_logging('this is a error info','error')
 
    def project_2():
 
        # do something
        project_2_logging('this is a debug info','debug')
        # do something
        project_2_logging('this is a warning info','warning')
        # do something
        project_2_logging('this is a critical info','error')
 
    project_1()
    project_2()
    #输出
2018-05-26 22:56:23 [project_1] DEBUG  this is a debug info
2018-05-26 22:56:23 [project_1] WARNING  this is a warning info
2018-05-26 22:56:23 [project_1] ERROR  this is a error info
2018-05-26 22:56:23 [project_2] DEBUG  this is a debug info
2018-05-26 22:56:23 [project_2] WARNING  this is a warning info
2018-05-26 22:56:23 [project_2] ERROR  this is a critical info

闭包思考:

1.闭包似优化了变量的传递,原来需要类对象完成的工作,闭包也可以完成;
2.由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存
### Python 闭包函数的定义 在 Python 中,闭包是一种特殊类型的函数结构。当一个嵌套函数在其作用域之外仍然能够记住并访问其外部函数的作用域中的变量时,这种机制就被称为闭包[^3]。具体来说,闭包由两部分组成:一个是函数本身,另一个是该函数所捕获的自由变量(即外部函数的局部变量)。因此,闭包的本质可以概括为“函数+引用环境”。 ```python def outer(): a = 5 # 外部函数的局部变量 def inner(): print(a) # 内部函数使用了外部函数的局部变量 return inner # 返回内部函数 func = outer() func() # 输出 5 ``` 上述代码展示了如何创建一个简单的闭包。`outer()` 是外部函数,在它的作用域中定义了一个名为 `a` 的局部变量以及一个嵌套函数 `inner()`。尽管 `outer()` 已经执行完毕,但由于闭包的存在,`inner()` 依然能访问 `a`。 --- ### Python 闭包的工作原理 闭包的核心在于延迟绑定和扩展作用域。通常情况下,局部变量会在函数退出后销毁;然而,如果某个局部变量被嵌套函数引用,则该变量会被保存下来以便后续使用。这一特性使得闭包能够在不同的上下文中保持状态信息[^2]。 以下是更详细的说明: 1. 当外部函数返回嵌套函数作为结果时,会形成一个闭包2. 嵌套函数保留对外部函数作用域中变量引用,即使外部函数已经结束运行。 3. 这种设计模式允许程序逻辑更加模块化,并支持某些复杂的计算需求。 下面的例子进一步阐释了这一点: ```python def multiplier(n): def multiply(x): return n * x # 访问外部函数参数 n return multiply double = multiplier(2) triple = multiplier(3) print(double(5)) # 输出 10 print(triple(5)) # 输出 15 ``` 这里,`multiplier` 创建两个独立的闭包——分别对应于乘以二的操作 (`double`) 和乘以三的操作 (`triple`)。这两个闭包各自维护了自己的副本 `n` 来存储倍率值。 --- ### Python 闭包的常见使用场景 #### 场景一:封装数据 利用闭包可以在无需引入全局变量的情况下隐藏一些敏感的数据成员。例如: ```python def counter(): count = 0 def increment(): nonlocal count count += 1 return count return increment cnt = counter() print(cnt()) # 输出 1 print(cnt()) # 输出 2 ``` 此案例通过闭包实现了计数器的功能,其中 `count` 变量仅限于闭包内部可见,从而保护了数据的安全性[^3]。 #### 场景二:模拟类的行为 虽然 Python 支持完整的 OOP 特性,但在轻量化或者快速原型开发阶段,有时可以用闭包代替类来简化编码流程。比如前面提到过的计算器例子实际上也可以看作是对简单对象模型的一种模仿。 #### 场景三:装饰器的基础组件 许多高级特性的实现离不开闭包的支持,其中包括但不限于装饰器的设计。装饰器本质上就是一个接受目标函数作为输入并将增强后的版本输出的新函数。借助闭包技术可以让原生函数携带额外的状态或行为而不改变原有接口签名[^4]。 ```python from functools import wraps def log_decorator(func): @wraps(func) def wrapper(*args, **kwargs): result = func(*args, **kwargs) print(f"{func.__name__} returned {result}") return result return wrapper @log_decorator def add(a, b): return a + b add(3, 4) # 输出 add returned 7 ``` 在这个样例里,我们构建了一款日志记录型装饰器,它基于闭包理念动态注入打印语句至任意指定的目标方法之中。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值