排行榜 统计
  • 文章总数:1276 篇
  • 评论总数:5 条
  • 分类总数:8 个
  • 最后更新:一天前

Python闭包机制介绍和安全防范

本文阅读 6 分钟
首页 安全资讯 正文

深盾安全

闭包机制介绍

闭包(Closure)是一个能够访问其自身定义时的词法作用域中的变量,即使该函数是在其词法作用域之外被执行的函数。

核心特性

基本特征

要创建一个闭包,必须同时满足以下三个条件:

嵌套函数

在函数内部定义另一个函数

引用外部变量

内部函数可以访问外部函数的变量

返回内部函数

外部函数执行完毕后,内部函数仍然可以访问外部函数的变量

适用场景

数据封装

可以隐藏内部状态

函数工厂

创建具有特定行为的函数

装饰器

修改函数行为

回调函数

保持上下文信息

关键要点

变量作用域

内部函数可以访问外部函数的变量,但不能直接修改,如果想要修改需要使用nonlocal关键字

延迟绑定

在循环中创建闭包时要注意变量捕获的时机

内存管理

闭包会保持对外部变量的引用,可能影响垃圾回收

性能考虑

闭包会占用额外的内存来存储捕获的变量

简单示例

示例代码

以经典的计数器闭包为例,参考代码如下:

def create_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

# 创建两个独立的计数器
counter1 = create_counter()
counter2 = create_counter()

print(f"第一个counter1的值: {counter1()}")
print(f"第一个counter1的值: {counter1()}")
print(f"第二个counter2的值: {counter2()}")
print(f"第一个counter1的值: {counter1()}")

示例详解

  1. 嵌套函数

create_counter作为外部函数,其内部定义了 counter函数。

  1. 引用了外部变量

counter 函数引用了外部函数 create_counter 的局部变量 count

  1. 返回内部函数

create_counter 返回了 counter 函数对象.

  1. 记忆效应

当 create_counter 执行完毕后,其局部作用域本应被销毁。但由于 counter引用了 count 变量,Python 会将这个变量 count 的生存期与闭包函数 counter1绑定,使其持续存在。每次调用 counter1,它操作的都是它记住的那个 count 变量。

  1. 独立性

创建两个计数器create_counter时,他们的值是独立存在的,两者是互不干扰。

示例结果

执行上述示例,输出结果如下:

图片

由此可以看到每次调用 create_counter() 都会创建一个全新的、独立的闭包实例,它们拥有各自独立的 count 变量,输出的也是自己独立的count状态。

nonlocal关键字

Python 中,如果内部函数只是读取外部变量的值,不需要 nonlocal。但如果需要修改它,则必须使用 nonlocal 关键字明确声明该变量不是内部函数的局部变量,而是来自外部嵌套作用域。

没有 nonlocal 的情况,在写到count = count + 1 时,就会提示count引用失败的错误。

def no_counter():
    count = 0
    def counter():
        count = count + 1 
        return count
    return counter
counter1 = create_counter()

__closure__属性

Python 为每个函数对象提供了一个 __closure__ 属性,可以通过它来查看闭包的内部情况。

  • 如果一个函数是闭包,__closure__ 属性会返回一个由单元格对象组成的元组。
  • 如果不是闭包,则该属性为 None
  • 单元格对象有一个 cell_contents 属性,可以获取到它存储的实际值。
ef test_func(x):
    def inner_func(y):
        return x + y 
    return inner_func的值

closure_value = test_func(3)

print(closure_value.__closure__)        # 输出单元格对象
print(closure_valueclosure_value.__closure__[0].cell_contents)  # 输出存储的实际值
print(closure_value(5))   # 输出inner_func的值

结果如图所示:

图片

常见应用场景

装饰器

装饰器本质上就是一个接收函数作为参数并返回一个闭包的高阶函数,是使用闭包最常见的场景,参考示例如下:

def my_decorator(func):
    def wrapper():
        print("function1")
        func()
        print("function2")
    return wrapper # 返回一个闭包

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

print(hello())

函数工厂

实现函数功能可以根据不同的参数,生成配置不同的函数,通过闭包,可以将变量"隐藏"起来,只能通过特定的函数进行访问和修改,相当于模拟了面向对象中的封装性,参考示例如下:

def fun_factory(exponent):
    def power(base):
        return base ** exponent
    return power

square = fun_factory(2) # 生成一个计算平方的函数
cube = fun_factory(3)   # 生成一个计算立方的函数

print(square(4)) # 16
print(cube(4))   # 64

安全防范

由于Python是一个面向字符串流的解释执行的特点,会引发了安全问题,使用者执行Python程序时, python解释器需要通过Python源码来解释执行,即便是编译成pyc,也有工具可以直接反编译回Python代码,因此保护Python脚本变得尤为关键。

Virbox Protector工具支持对py脚本进行字节码级别保护,可以防止源码泄露,参考文档Python程序保护最佳实践。

本文经授权后发布,本文观点不代表立场
免责声明:文章内容不代表本站立场,本站不对其内容的真实性、完整性、准确性给予任何担保、暗示和承诺,仅供读者参考,文章版权归原作者所有。避免网络欺诈,本站不倡导任何交易行为。如您私自与本站转载自公开互联网中的资讯内容中提及到的个人或平台产生交易,则需自行承担后果。本站在注明来源的前提下推荐原文至此,仅作为优良公众、公开信息分享阅读,不进行商业发布、发表及从事营利性活动。如本文内容影响到您的合法权益(内容、图片等),请及时联系本站,我们会及时删除处理。
-- 展开阅读全文 --
抖音直播号抖音小号购买网,微信小号——抖音粉丝号交易出售正规平台
« 上一篇 09-01
心磁图技术:无创精准定位运动爱好者心律失常的新方法
下一篇 » 09-02