Python 中的块范围

2025-02-27 09:07:00
admin
原创
49
摘要:问题描述:当你使用其他语言编写代码时,你有时会创建一个块作用域,如下所示:statement ... statement { statement ... statement } statement ... statement 其中一个目的(众多目的之一)是提高代码的可读性:显示某些语句...

问题描述:

当你使用其他语言编写代码时,你有时会创建一个块作用域,如下所示:

statement
...
statement
{
    statement
    ...
    statement
}
statement
...
statement

其中一个目的(众多目的之一)是提高代码的可读性:显示某些语句形成逻辑单元或某些局部变量仅在该块中使用。

在 Python 中是否有一种惯用的方法可以做同样的事情?


解决方案 1:

不,没有语言支持创建块范围。

以下构造创建范围:

  • 模块

  • 班级

  • 函数(包括 lambda)

  • 生成器表达式

  • 理解(字典、集合、列表(在 Python 3 中))

解决方案 2:

Python 中的惯用方法是保持函数简短。如果您认为需要这样做,请重构您的代码!:)

Python 为每个模块、类、函数、生成器表达式、字典推导、集合推导以及 Python 3.x 中的每个列表推导都创建了新的作用域。除此之外,函数内部没有嵌套的作用域。

解决方案 3:

你可以在 Python 中执行类似于 C++ 块作用域的操作,方法是在函数内部声明一个函数,然后立即调用它。例如:

def my_func():
    shared_variable = calculate_thing()

    def do_first_thing():
        ... = shared_variable
    do_first_thing()

    def do_second_thing():
        foo(shared_variable)
        ...
    do_second_thing()

如果您不确定为什么要这样做,那么这个视频可能会说服您。

基本原则是尽可能严格地限定一切的范围,并且不将任何“垃圾”(额外的类型/函数)引入到比绝对需要的更宽的范围中 -do_first_thing()例如,没有其他东西愿意使用该方法,因此它不应该被限定在调用函数之外的范围。

解决方案 4:

我同意没有块作用域。但是 Python 3 中有一个地方让它看起来好像有块作用域。

发生了什么事导致出现这种表情?

这在 Python 2 中可以正常工作,但是为了在 Python 3 中停止变量泄漏,他们使用了这个技巧,并且这个更改使它看起来好像在这里具有块范围。

让我解释一下。


按照作用域的思想,当我们在同一作用域内引入同名的变量时,其值应该被修改。

这是在 Python 2 中发生的情况:

>>> x = 'OLD'
>>> sample = [x for x in 'NEW']
>>> x
'W'

但是在Python 3中,即使引入了同名变量,也不会覆盖,而且列表推导式由于某种原因就像一个沙箱,似乎在其中创建了一个新的作用域。

>>> x = 'OLD'
>>> sample = [x for x in 'NEW']
>>> x
'OLD'

这个答案与回答者ThomasH 的陈述 相悖,创建范围的唯一方法是函数、类或模块,因为这看起来像是创建新范围的另一个地方。

解决方案 5:

我已经找到一个解决方案,它具有最简单的界面并且需要在代码中引入最少的额外名称。

from scoping import scoping
a = 2
with scoping():
    assert(2 == a)
    a = 3
    b = 4
    scoping.keep('b')
    assert(3 == a)
assert(2 == a)
assert(4 == b)

https://pypi.org/project/scoping/

解决方案 6:

为了完整性:您可以使用del结束局部变量的作用域。另请参阅Python 中的 del 何时有用?。不过,这肯定不是惯用的。

statement
statement

# Begin block
a = ...
b = ...
statement
statement
del a, b
# End block

statement

解决方案 7:

模块(和包)是一种很好的 Python 方式,可以将程序划分为单独的命名空间,这似乎是这个问题的一个隐含目标。事实上,当我学习 Python 的基础知识时,我对缺少块作用域功能感到沮丧。然而,一旦我理解了 Python 模块,我就可以更优雅地实现我之前的目标,而不需要块作用域。

为了激励人们,并为他们指明正确的方向,我认为提供一些 Python 作用域构造的明确示例很有用。首先,我解释了我使用 Python 类实现块作用域的失败尝试。接下来,我解释了如何使用 Python 模块实现更有用的功能。最后,我概述了包在加载和过滤数据方面的实际应用。

尝试使用类来块级作用域

有一会儿,我以为我已经通过将代码粘贴在类声明中来实现块范围:

x = 5
class BlockScopeAttempt:
    x = 10
    print(x) # Output: 10
print(x) # Output: 5

不幸的是,当定义一个函数时,这就失效了:

x = 5 
class BlockScopeAttempt: 
    x = 10
    print(x) # Output: 10
    def printx2(): 
        print(x) 
    printx2() # Output: 5!!!

这是因为在类中定义的函数使用全局范围。解决此问题的最简单(但不是唯一)方法是明确指定类:

x = 5 
class BlockScopeAttempt: 
    x = 10
    print(x) # Output: 10
    def printx2(): 
        print(BlockScopeAttempt.x)  # Added class name
    printx2() # Output: 10

这不太优雅,因为必须根据函数是否包含在类中来以不同的方式编写函数。

使用 Python 模块获得更好的结果

模块与静态类非常相似,但根据我的经验,模块要简洁得多。要对模块执行相同操作,我my_module.py在当前工作目录中创建一个名为的文件,其内容如下:

x = 10
print(x) # (A)

def printx():
    print(x) # (B)

def alter_x():
    global x
    x = 8

def do_nothing():
    # Here x is local to the function.
    x = 9

然后在我的主文件或交互式(例如 Jupyter)会话中,我这样做

x = 5
from my_module import printx, do_nothing, alter_x  # Output: 10 from (A)
printx()  # Output: 10 from (B)
do_nothing()
printx()  # Output: 10
alter_x()
printx()  # Output: 8
print(x) # Output: 5
from my_module import x  # Copies current value from module
print(x) # Output: 8
x = 7
printx()  # Output: 8
import my_module
my_module.x = 6
printx()  # Output: 6

作为解释,每个 Python 文件都定义一个具有自己的全局命名空间的模块。该import my_module命令允许您使用语法访问此命名空间中的变量.。我认为模块就像静态类。

如果你在交互式会话中使用模块,则可以在开始时执行这两行

%load_ext autoreload
%autoreload 2

当相应文件被修改时,模块将自动重新加载。

加载和过滤数据的包

包的概念是模块概念的轻微扩展。包是一个包含__init__.py文件(可能是空白的)的目录,该文件在导入时执行。可以使用.语法访问此目录中的模块/包。

对于数据分析,我经常需要读取大型数据文件,然后以交互方式应用各种过滤器。读取文件需要几分钟,所以我只想做一次。根据我在学校学到的面向对象编程知识,我过去认为应该将过滤和加载的代码编写为类中的方法。这种方法的一个主要缺点是,如果我重新定义过滤器,我的类的定义就会发生变化,所以我必须重新加载整个类,包括数据。

现在使用 Python,我定义了一个名为 的包my_data,其中包含名为load和 的子模块filter。在其中filter.py我可以进行相对导入:

from .load import raw_data

如果我修改filter.py,那么autoreload将检测到更改。它不会重新加载load.py,所以我不需要重新加载我的数据。这样我就可以在 Jupyter 笔记本中原型化我的过滤代码,将其包装为一个函数,然后直接从我的笔记本中剪切粘贴到filter.py。搞清楚这一点彻底改变了我的工作流程,让我从一个怀疑论者变成了“Python 之禅”的信徒。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2974  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1836  
  PLM(产品生命周期管理)系统在企业的产品研发、生产与管理过程中扮演着至关重要的角色。然而,在实际运行中,资源冲突是经常会遇到的难题。资源冲突可能导致项目进度延迟、成本增加以及产品质量下降等一系列问题,严重影响企业的效益与竞争力。因此,如何有效应对PLM系统中的资源冲突,成为众多企业关注的焦点。接下来,我们将详细探讨5...
plm项目管理系统   47  
  敏捷项目管理与产品生命周期管理(PLM)的融合,正成为企业在复杂多变的市场环境中提升研发效率、增强竞争力的关键举措。随着技术的飞速发展和市场需求的快速更迭,传统的研发流程面临着诸多挑战,而将敏捷项目管理理念融入PLM,有望在2025年实现研发流程的深度优化,为企业创造更大的价值。理解敏捷项目管理与PLM的核心概念敏捷项...
plm项目   47  
  模块化设计在现代产品开发中扮演着至关重要的角色,它能够提升产品开发效率、降低成本、增强产品的可维护性与可扩展性。而产品生命周期管理(PLM)系统作为整合产品全生命周期信息的关键平台,对模块化设计有着强大的支持能力。随着技术的不断发展,到 2025 年,PLM 系统在支持模块化设计方面将有一系列令人瞩目的技术实践。数字化...
plm软件   48  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用