首页 > 编程语言 >python | 一文看懂Python闭包机制与变量作用域规则

python | 一文看懂Python闭包机制与变量作用域规则

时间:2024-12-20 20:01:05浏览次数:6  
标签:闭包 函数 作用域 python func print 变量

本文来源公众号“python”,仅用于学术分享,侵权删,干货满满。

原文链接:一文看懂Python闭包机制与变量作用域规则

在Python编程中,闭包和变量作用域是两个重要的概念。闭包(Closure)是一种函数对象,它能够记住并捕获创建时的环境变量,因此即使在函数调用结束后,闭包也能访问这些变量。闭包与变量作用域密切相关,而变量作用域则决定了变量在代码中的可见性和生命周期。理解闭包和变量作用域可以编写更灵活、更模块化的代码,同时也能提高对Python内部机制的理解。

变量作用域

在Python中,变量作用域是指变量在代码中的可访问范围。

  1. Local(局部作用域):定义在函数内部的变量,仅在函数内部可见。

  2. Enclosing(闭包作用域):嵌套函数的外层函数作用域。

  3. Global(全局作用域):模块级别的变量,在整个模块中可见。

  4. Built-in(内置作用域):Python的内置名称空间,包含lenrange等Python内置函数。

这四种作用域遵循LEGB(Local、Enclosing、Global、Built-in)规则,即在访问变量时,Python会按此顺序依次查找变量。

LEGB作用域规则

以下代码展示了LEGB作用域查找规则的具体应用:

x = "global"

def outer():
    x = "enclosing"

    def inner():
        x = "local"
        print(x)

    inner()

outer()  # 输出:local
print(x)  # 输出:global

在这个示例中,Python首先在inner()函数的局部作用域中查找x,找到x = "local"并打印;如果没有找到,则会继续在outer()的闭包作用域、全局作用域和内置作用域中查找。

什么是闭包

闭包是指在一个函数内部定义了一个嵌套函数,且这个嵌套函数引用了外层函数的变量。当外层函数执行结束后,这些引用的变量依然存在于嵌套函数的环境中,即使外层函数的作用域不再存在,嵌套函数仍然可以访问这些变量。

闭包的特点是“函数对象+环境变量”,环境变量是函数定义时捕获的变量,它使得函数可以在其定义环境之外的地方使用。

闭包的构成条件

  1. 嵌套函数:函数内部定义了另一个函数。

  2. 外层函数返回嵌套函数:外层函数返回嵌套函数,以便在外部调用。

  3. 嵌套函数使用了外层函数的变量:嵌套函数引用了外层函数中的变量,使得这些变量在外层函数作用域结束后仍然有效。

下面的代码展示了一个闭包的基本示例:

def outer_func(x):
    def inner_func(y):
        return x + y
    return inner_func

# 创建闭包
closure = outer_func(10)
print(closure(5))  # 输出:15

在这个例子中,outer_func返回了一个inner_func闭包。即使outer_func的执行结束,但inner_func仍然能够访问到outer_func中的变量x,从而成功返回x + y的结果。

闭包的实际应用

1. 实现带状态的函数

闭包可以保存变量的状态,因此常用于实现带状态的函数。

以下代码展示了如何使用闭包实现一个计数器函数:

def counter():
    count = 0

    def increment():
        nonlocal count
        count += 1
        return count

    return increment

# 创建计数器闭包
counter_func = counter()
print(counter_func())  # 输出:1
print(counter_func())  # 输出:2
print(counter_func())  # 输出:3

在这个示例中,counter函数返回了increment闭包。每次调用increment时,闭包会更新count变量,从而实现计数器功能。通过使用nonlocal关键字,我们可以在嵌套函数中修改外层函数的变量。

2. 延迟计算

闭包也可以用于延迟计算,即在需要时再执行特定操作。

以下代码展示了一个简单的延迟计算示例:

def lazy_multiply(x):
    def multiply(y):
        return x * y
    return multiply

# 创建延迟计算闭包
double = lazy_multiply(2)
triple = lazy_multiply(3)
print(double(5))  # 输出:10
print(triple(5))  # 输出:15

在这个例子中,lazy_multiply返回了一个multiply闭包,使得我们可以创建不同的乘法操作对象,如doubletriple,从而在需要时执行乘法运算。

3. 封装对象行为

闭包还可以用于封装对象的行为,使得数据和操作的访问仅限于闭包内部。

以下代码展示了一个基于闭包实现的简单账户系统:

def create_account(balance):
    def deposit(amount):
        nonlocal balance
        balance += amount
        return balance

    def withdraw(amount):
        nonlocal balance
        if balance >= amount:
            balance -= amount
            return balance
        else:
            return "余额不足"

    return deposit, withdraw

# 创建账户闭包
deposit_func, withdraw_func = create_account(100)
print(deposit_func(50))     # 输出:150
print(withdraw_func(30))    # 输出:120
print(withdraw_func(200))   # 输出:余额不足

在这个示例中,create_account返回两个闭包depositwithdraw,分别用于存款和取款操作。通过闭包,实现了对账户余额的封装,确保了余额变量的私密性。

变量作用域与闭包

在闭包中,变量作用域会影响变量的查找和修改行为。Python中,嵌套函数对外层变量的访问遵循LEGB规则,但如果想在闭包中修改外层作用域的变量,需要使用nonlocal关键字。如果闭包想要修改全局变量,需要使用global关键字。

nonlocal关键字

在闭包中,nonlocal关键字用于声明外层非全局作用域的变量,使得闭包可以修改它的值。

def outer():
    x = 10

    def inner():
        nonlocal x
        x += 1
        return x

    return inner

# 创建闭包
increment = outer()
print(increment())  # 输出:11
print(increment())  # 输出:12

在这个示例中,nonlocal x允许inner闭包修改outer函数中的x变量。否则,x将被视为inner函数的局部变量,无法修改外层作用域的值。

闭包与lambda表达式

闭包不仅可以用在普通函数中,还可以与lambda表达式结合使用。lambda表达式通常用于创建简洁的闭包,使代码更加简洁和高效。

lambda闭包示例

以下代码展示了一个使用lambda表达式实现的闭包示例:

def power(n):
    return lambda x: x ** n

# 创建平方和立方闭包
square = power(2)
cube = power(3)
print(square(4))  # 输出:16
print(cube(4))    # 输出:64

在这个例子中,power函数返回了一个lambda闭包,使得我们可以生成不同次幂的计算函数,如平方和立方函数。这种方式使代码更为简洁。

闭包的优缺点

优点缺点
允许函数拥有私有变量,提高封装性使用不当可能导致代码难以理解
可以创建带状态的函数若闭包中包含大量数据,可能增加内存消耗
提高函数的灵活性和可重用性不易调试,可能出现意料之外的错误

总结

闭包和变量作用域是Python编程中非常重要的概念。闭包是一种函数对象,即使在外层函数执行完毕后,嵌套函数依然能够访问其创建时的环境变量,能够实现带状态的函数和数据的封装。变量作用域决定了变量在不同范围内的可访问性和生命周期,遵循LEGB规则,即局部、闭包、全局和内置作用域的顺序。理解闭包与作用域的关系,不仅能提高代码的封装性和复用性,还能帮助编写更简洁、逻辑清晰的代码。掌握这些特性可以在编写带状态的函数、延迟计算、以及实现封装时更加得心应手。

THE END !

文章结束,感谢阅读。您的点赞,收藏,评论是我继续更新的动力。大家有推荐的公众号可以评论区留言,共同学习,一起进步。

标签:闭包,函数,作用域,python,func,print,变量
From: https://blog.csdn.net/csdn_xmj/article/details/144139657

相关文章

  • Python网络爬虫技术详解与实战案例
    Python网络爬虫技术详解与实战案例引言网络爬虫(WebCrawler)是一种自动化程序,用于在互联网上收集数据。通过向网页发送HTTP请求,获取网页数据,然后提取和分析网页内容,网络爬虫能够实现数据收集、信息提取和数据分析等多种应用场景。Python作为一种功能强大且易于学习的编程语......
  • python毕设 理发预约系统程序+论文
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、选题背景关于理发预约系统的研究,现有研究多集中在通用的预约系统开发或大型服务行业预约系统的优化方面,专门针对理发行业的预约系统研究较少。......
  • Tableau and Python Visualization for finance
    DATAANALYTICS&VISUALIZATIONFORFINANCE2024-2025Mission3(Individual)–TableauandPythonDeadline:December16th2024,23:59(CET)Inthisindividualassignment,youwillhavetheopportunitytoapplybothyourTableauandPythonskills working......
  • 使用 Python 和 Tesseract OCR 识别验证码(增强版)
    安装Tesseract和Python依赖同样地,你需要安装TesseractOCR和相关的Python库:更多内容访问ttocr.com或联系1436423940安装Tesseract在Windows上,你可以从Tesseract官方GitHub下载Tesseract安装包并按照说明进行安装。安装完成后,请确保将Tesseract的安装路径......
  • 《基于 Python 的网页爬虫详细教程》
    一、引言在当今信息时代,从互联网上获取大量有价值的数据对于许多领域的研究和分析至关重要。网页爬虫是一种自动化程序,可以从网页上抓取所需的数据。Python作为一种强大的编程语言,拥有丰富的库和工具,使得网页爬虫的开发变得相对容易。本文将详细介绍如何使用Python进行网......
  • python 函数方法try中某一条代码异常如何主动抛出该异常得原因【两种方法】
    在Python中,当函数方法中的某一条代码引发异常时,你通常会让Python解释器自动抛出该异常,并在except块中捕获它。然而,如果你想要主动抛出异常(可能是因为你检测到了某个错误条件,或者你想要从某个特定的代码点中断执行并通知调用者),你可以使用raise语句。但是,如果你想要抛出与原始异常......
  • python 函数方法try 用法 案例
    在Python中,try语句用于捕获和处理在代码块执行过程中可能发生的异常。try语句后面通常会跟着一个或多个except子句来指定不同类型的异常处理逻辑,以及一个可选的else子句来指定如果没有异常发生时要执行的代码,还有一个可选的finally子句来指定无论是否发生异常都要执行的清理代码。......
  • python 中try多异常处理
    在Python中,异常处理是通过try、except、else和finally这几个关键字来实现的。下面是一个详细的异常处理例子,它涵盖了这些关键字的用法:defdivide_numbers(a,b):"""这个函数尝试将两个数相除,并处理可能出现的异常。参数:a(intorfloat):被除数b......
  • 实现Python将csv数据导入到Neo4j
    目录一、获取数据集1.1获取数据集1.2以“记事本”方式打开文件​编辑1.3 另存为“UTF-8”格式文件1.4选择“是”二、打开Neo4j并运行2.1创建新的Neo4j数据库2.2分别设置数据库名和密码​编辑 2.3启动Neo4j数据库2.4打开Neo4j数据库 2.5运行查看该数据......
  • python可以在命令行上运行的小工具模块
    以下是Python可以在命令行上运行的一些小工具模块,以及它们的用途和用法示例。这些模块大多属于Python的标准库,因此无需额外安装即可使用。模块用途用法示例http.server启动一个简单的Web服务器,用于共享文件或提供简单的Web服务python-mhttp.server在默认端口8000......