python---闭包(Closure)


闭包是Python中一个强大且有用的概念,它指的是一个函数能够记住并访问其词法作用域(lexical scope)中的变量,即使该函数在其作用域之外执行。

闭包的基本概念

闭包需要满足三个条件:
1、必须有一个嵌套函数(函数内部定义函数)

2、嵌套函数必须引用外部函数中的变量

3、外部函数必须返回嵌套函数

代码示例:

def outer_function(msg):
    # 外部函数的变量
    message = msg
    
    def inner_function():
        # 内部函数访问外部函数的变量
        print(message)
    
    # 返回内部函数(不执行)
    return inner_function

# 直接调用
outer_function("Hello, Closure!")()

# 创建闭包
my_func = outer_function("Hello, Closure!")
my_func()  # 输出: Hello, Closure!

闭包的特点

1、记住状态:闭包可以记住创建时的环境状态

2、数据封装:可以用于隐藏数据,实现类似面向对象的私有变量

3、延迟执行:可以在需要时才执行内部函数

实际应用示例

计数器实现:

def counter():
    count = 0
    
    def increment():
        nonlocal count  # 声明count不是局部变量
        count += 1
        return count
    
    return increment

# 创建计数器
counter1 = counter()
print(counter1())  # 1
print(counter1())  # 2
print(counter1())  # 3

# 另一个独立的计数器
counter2 = counter()
print(counter2())  # 1

输出显示:

1
2
3
1

函数工厂:

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

square = power_factory(2)
cube = power_factory(3)

print(square(5))  # 25
print(cube(5))    # 125

注意事项

1、变量绑定:闭包中引用的变量是在运行时才查找的,不是定义时的值

def create_multipliers():
    return [lambda x: i * x for i in range(5)]

for multiplier in create_multipliers():
    print(multiplier(2))  # 全部输出8,因为i最后是4

问题原因:
1、这里所有的 lambda 函数都共享同一个变量 i

2、当这些函数被调用时,它们查找的是 i 的当前值(不是创建时的值)

3、循环结束后 i 的值是 4,所以所有函数都计算 4 * 2 = 8

修正方法:

def create_multipliers():
    return [lambda x, i=i: i * x for i in range(5)]

修正原理:
1、这里我们在 lambda 函数中使用了默认参数 i=i

2、默认参数在函数定义时(即循环的每次迭代时)就被求值并固定

3、所以每个 lambda 函数都记住了自己创建时的 i 值

4、这样就能得到预期的 0 * 2, 1 * 2, 2 * 2, 3 * 2, 4 * 2 结果

2、内存消耗:闭包会保持外部变量的引用,可能导致内存无法释放

3、nonlocal关键字:Python 3中引入,用于在嵌套函数中修改外部函数的变量

### 如何计算NFA的ε-闭包 ε-闭包是指从某个状态出发,通过任意数量的ε(空字符串)转换能够到达的所有状态集合。这是构建NFA到DFA的过程中非常重要的一步。 #### 定义 对于给定的状态 \( q \),其 ε-闭包表示为 \( E(q) \),即从状态 \( q \) 出发仅通过 ε 转移所能达到的所有状态组成的集合[^1]。 #### 方法描述 为了计算 NFA 中某状态的 ε-闭包,可以采用广度优先搜索 (BFS) 或深度优先搜索 (DFS) 来遍历所有可能的 ε 过渡路径: 1. 初始化一个队列并加入起始状态 \( q_0 \)。 2. 创建一个空集合用于存储已访问过的状态,并将初始状态 \( q_0 \) 添加至该集合。 3. 当队列不为空时: - 从队列中取出当前状态 \( q_i \)- 查找从 \( q_i \) 出发的所有 ε 转移到达的状态。 - 将这些新发现的状态逐一加入队列以及已访问集合中(如果它们尚未被处理过)。 4. 遍历完成后,返回已访问集合作为最终的结果——这就是所求的 ε-闭包。 #### 示例代码实现 下面是基于 Python 的一种简单实现方式来演示上述过程: ```python def epsilon_closure(nfa, start_state): closure = set() # 存储结果的集合 queue = [] # 辅助队列 closure.add(start_state) queue.append(start_state) while queue: current_state = queue.pop(0) # 获取所有的epsilon转移目标 epsilons = nfa.get_transitions(current_state, 'eps') or [] for state in epsilons: if state not in closure: closure.add(state) queue.append(state) return list(closure) ``` 此函数接收两个参数:`nfa` 是代表非确定有限自动机的对象;它应提供 `get_transitions(from_state, symbol)` 方法用来查询特定状态下对应符号(symbol)可转移到哪些其他状态。另一个参数则是希望获取其ε-闭包的那个具体状态名称或ID[^4]。 ### 结论 利用以上介绍的方法即可有效地完成对任何指定节点关于ε跃迁可达性的全面探索工作,从而得到完整的ε-closure数据结构形式输出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值