Python变量在循环示例中的作用域

Python变量在循环示例中的作用域,python,Python,我是Python新手,对循环中声明的变量的范围感到困惑。我见过一些例子,但在我的具体案例中,我很难理解 例如,我看到了以下代码段: 我基本上以非常相同的方式重复上面的代码,但在循环中执行不同的语句这些相似的代码段在我的\uuuu main\uuuuu中一个接一个地出现。我的问题是:在重复的代码中,是否需要为存档、id、文件、文件、输出文件的变量赋予新名称?会有冲突还是什么?有什么好的做法值得注意吗?假设此代码在函数中,那么变量的作用域一直到函数的末尾。如果此代码在模块级别,那么变量的作用域就是模

我是Python新手,对循环中声明的变量的范围感到困惑。我见过一些例子,但在我的具体案例中,我很难理解

例如,我看到了以下代码段:


我基本上以非常相同的方式重复上面的代码,但在循环中执行不同的语句这些相似的代码段在我的
\uuuu main\uuuuu
中一个接一个地出现。我的问题是:在重复的代码中,是否需要为
存档
id
文件
文件
输出文件
的变量赋予新名称?会有冲突还是什么?有什么好的做法值得注意吗?

假设此代码在函数中,那么变量的作用域一直到函数的末尾。如果此代码在模块级别,那么变量的作用域就是模块(也称为全局)作用域

你不必使用不同的名字。以下代码只会在不同的时间将不同的对象分配给
存档
变量:

with ZipFile(self.archive_name, "r") as archive:
    print(id(archive))

with ZipFile(self.archive_name, "r") as archive:
    print(id(archive))
这相当于:

archive = ZipFile(self.archive_name, "r")
with archive:
    print(id(archive))
archive = ZipFile(self.archive_name, "r")
with archive:
    print(id(archive))
也就是说,与
with
语句和循环关联的块并不定义变量的作用域,它们只是赋值。您应该看到为不同对象的ID打印了两个不同的值

请注意,由于示例代码使用
id
作为变量名,因此使用内置函数
id
的示例时应小心

有什么好的做法需要牢记吗

有可能误入固执己见的领域:

  • 很少在循环外部使用循环变量的值。因此,通常可以在函数后面的新循环中再次使用相同的循环变量,但一般来说,在再次使用该变量之前,应该检查该变量名称在函数中的所有用法。对于模块级代码来说,这更糟糕:在添加第二个循环之前,您需要确保模块的外部用户不依赖第一个循环中留下的值的变量
  • 除非对象在两个不同的位置提供完全相同的角色,否则尽管稍后在函数中重复使用变量是安全的,但仍然可能有点混乱
  • 显然,在将代码复制粘贴两次到函数中之前,您需要合理地确定在您的特定情况下,重复(可能有一些更改)确实比定义另一个函数并调用它两次要好

通常,缩进块不会启动新范围。只有模块、类和函数定义了新的作用域。(在Python3中,list/set/dict理解中的索引是理解的局部索引。)


例如,在您的示例中,
archive
在出现
with
语句的整个模块/类/函数的范围内,就像在
with
语句体中首次分配的任何变量一样。如果
with
语句位于模块范围内,则所有赋值都将分配给模块全局变量。如果它位于类定义的顶层,则它们都是类属性。如果它(很可能)是在函数或方法声明中定义的,那么它们是该函数的本地部分。

谢谢您的精彩回答。只是需要澄清;你说‘如果这段代码在模块级,那么变量的作用域就是模块(也称为全局)作用域’,这就是我的代码所在的地方。所以,‘不必使用不同的名称’。这使我困惑。我的意思是,既然它是全局范围,
id
变量在第一次声明时,它会不会一直“保持”它的值直到结束??抱歉,如果我理解得太慢:)@hask.duke:如果此代码处于模块级别,则
id
变量将保留您给它的值,直到文件结束,或者直到您为其分配新值(这是您的第二个for循环将执行的操作)。此外,导入您的模块的其他模块将能够访问其最终值,即
your\u module\u name.id
。这是避免在模块级编写大量代码的原因之一。在自动生成的文档中查看循环变量,在调试器中使用模块时调用
dir()
,诸如此类的东西,对任何人都没有帮助。因此,如果我理解正确,出现在第二个代码段上的
id
变量没有问题,主要是因为它已重新初始化?也就是说,如果had在第一个代码段结束后立即调用id而不初始化它,那么它将保留在第一个代码段的第一个循环结束时得到的任何值???@hask.duke:是的,您可以在循环结束后立即访问一个循环变量,并且它保存在循环最后一次重复中得到的任何值。尽管作为一种特殊情况,如果循环执行零次,因为
data.items()
返回一个空列表或其他什么,那么循环变量根本不会被赋值,因此如果这是函数中的第一次使用,那么它就没有定义。完美。非常感谢您的澄清。修改了我的问题,添加了关于这些类似代码段所在位置的信息。
archive = ZipFile(self.archive_name, "r")
with archive:
    print(id(archive))
archive = ZipFile(self.archive_name, "r")
with archive:
    print(id(archive))