
一、定义
在 Python 中,当一个函数内部定义的函数引用了外部函数的局部变量时,就形成了一个闭包。这个内部函数可以访问并修改外部函数的局部变量,而这些局部变量的状态会一直被保存在闭包中,即使外部函数已经执行完毕。
这种机制使得闭包可以实现一些特殊的功能,例如记忆化(Memoization)和实现私有变量等。闭包可以在函数内部保存一些状态,并且这些状态对外部是不可见的,从而实现了一定程度上的信息隐藏和封装。
- def outer_function():
- x = 10
- def inner_function():
- nonlocal x # 声明使用外部函数的局部变量 x
- x += 5
- return x
- return inner_function
-
- closure = outer_function()
- print(closure()) # 输出结果为 15
- print(closure()) # 输出结果为 20
在这个示例中,inner_function 就是一个闭包,它引用了外部函数 outer_function 中的局部变量 x。每次调用 closure() 都会修改并返回 x 的值,而这个状态是被保存在闭包中的。

二、通过一个例子全面剖析一下闭包这个概念。
需求:实现银行系统的余额变化。
方式一:全局变量+函数
- balance = 1000
- def deposit(amount):
- global balance
- balance += amount
- print(f"成功存入 {amount} 元,当前余额为 {balance} 元")
-
- def withdraw(amount):
- global balance
- if amount <= balance:
- balance -= amount
- print(f"成功取出 {amount} 元,当前余额为 {balance} 元")
- else:
- print("余额不足,取款失败")
-
- def check_balance():
- print(f"当前余额为 {balance} 元")
-
- # 存款和取款操作
- deposit(500) # 存入 500 元
- withdraw(200) # 取出 200 元
- balance=10
- deposit(500) # 存入 500 元
- check_balance() # 查看余额
结果
成功存入 500 元,当前余额为 1500 元
成功取出 200 元,当前余额为 1300 元
成功存入 500 元,当前余额为 510 元
当前余额为 510 元
缺点:全局变量不安全,可以被随意访问和修改。
使用全局变量的方式虽然可以实现功能,但存在一些潜在问题:
可变性:全局变量的值是可变的,任何函数都可以直接修改它,这增加了程序出错的可能性,尤其在大型程序中更容易出现问题。
可见性:全局变量对整个程序都是可见的,这意味着任何部分都可以修改它,从而导致程序行为难以预测。
扩展性:如果需要管理多个账户,全局变量的方式就显得力不从心,因为很难将多个账户的信息独立地封装起来。
方案二:类
- class BankAccount:
- def __init__(self, initial_balance):
- self.balance = initial_balance
-
- def deposit(self, amount):
- self.balance += amount
- print(f"成功存入 {amount} 元,当前余额为 {self.balance} 元")
-
- def withdraw(self, amount):
- if amount <= self.balance:
- self.balance -= amount
- print(f"成功取出 {amount} 元,当前余额为 {self.balance} 元")
- else:
- print("余额不足,取款失败")
-
- def check_balance(self):
- print(f"当前余额为 {self.balance} 元")
-
- # 创建账户
- account = BankAccount(1000)
- account.balance=550
- # 存款和取款操作
- account.deposit(500) # 存入 500 元
- account.withdraw(200) # 取出 200 元
- account.check_balance() # 查看余额
结果
成功存入 500 元,当前余额为 1050 元
成功取出 200 元,当前余额为 850 元
当前余额为 850 元
缺点:共有属性也能被对象访问修改,不安全。
方案三:类+私有属性
- class BankAccount:
- def __init__(self, initial_balance):
- self.__balance = initial_balance
-
- def deposit(self, amount):
- self.__balance += amount
- print(f"成功存入 {amount} 元,当前余额为 {self.__balance} 元")
-
- def withdraw(self, amount):
- if amount <= self.__balance:
- self.__balance -= amount
- print(f"成功取出 {amount} 元,当前余额为 {self.__balance} 元")
- else:
- print("余额不足,取款失败")
-
- def check_balance(self):
- print(f"当前余额为 {self.__balance} 元")
-
- account = BankAccount(1000)
- account.deposit(500)
-
- account.withdraw(200)
- account.check_balance()
结果:
成功存入 500 元,当前余额为 1500 元
成功取出 200 元,当前余额为 1300 元
当前余额为 1300 元
问题得到解决。
方案四:闭包
- def create_account(initial_balance):
- balance = initial_balance
- def deposit(amount):
- nonlocal balance
- balance += amount
- print(f"成功存入 {amount} 元,当前余额为 {balance} 元")
-
- def withdraw(amount):
- nonlocal balance
- if amount <= balance:
- balance -= amount
- print(f"成功取出 {amount} 元,当前余额为 {balance} 元")
- else:
- print("余额不足,取款失败")
-
- def check_balance():
- print(f"当前余额为 {balance} 元")
-
- return deposit, withdraw, check_balance
-
- # 创建账户
- deposit, withdraw, check_balance = create_account(1000)
-
- # 存款和取款操作
- deposit(500) # 存入 500 元
- print(deposit)
- withdraw(200) # 取出 200 元
- check_balance() # 查看余额
-
- # 创建账户
- deposit1, withdraw1, check_balance1 = create_account(10000)
- # 存款和取款操作
- deposit1(500) # 存入 500 元
- print(deposit1)
- withdraw1(200) # 取出 200 元
- check_balance1() # 查看余额
结果
成功存入 500 元,当前余额为 1500 元
成功取出 200 元,当前余额为 1300 元
当前余额为 1300 元
成功存入 500 元,当前余额为 10500 元
成功取出 200 元,当前余额为 10300 元
当前余额为 10300 元
完美解决了问题
三、辨析
闭包和类是两种不同的概念,它们在编程中有着不同的用途和特点。
闭包(Closure)是指可以在其词法作用域之外执行的函数,但仍然保持对其作用域内变量的引用。换句话说,闭包是函数及其相关的引用环境的组合。闭包可以用来封装状态、实现私有变量等功能。在 Python 中,当一个函数内部定义的函数引用了外部函数的局部变量时,就形成了一个闭包。
类(Class)则是面向对象编程中的重要概念,它用来描述具有相似属性和行为的对象的模板。类由属性(成员变量)和方法(成员函数)组成,可以通过实例化来创建对象,并且支持继承、多态等面向对象的特性。类的主要作用是封装数据和操作数据的方法,以及实现代码复用和抽象。
下面是闭包和类的一些区别:
封装方式不同:闭包是一种函数式编程的封装方式,通过函数和其引用环境来封装状态和行为;类是一种面向对象编程的封装方式,通过属性和方法来封装数据和操作。
状态的保存方式不同:闭包通过引用环境来保存状态,而类通过实例变量和类变量来保存状态。
范围不同:闭包通常用于封装一些局部状态,提供函数式编程的功能;类则通常用于描述对象的行为和属性,提供面向对象编程的特性。
总的来说,闭包和类都是用于封装和抽象的工具,但其应用场景和实现方式有所不同。在实际编程中,可以根据具体的需求和问题选择合适的工具来实现相应的功能。

