"with"语句内的变量作用域是什么?

88

我正在使用以下代码从Python中仅读取firstline

with open(file_path, 'r') as f:
    my_count = f.readline()
print(my_count)

我对变量my_count的作用域有些困惑。虽然打印工作得很好,但是是否最好先在with语句之外做一些像my_count = 0这样的事情呢?(例如,在C中,我习惯于首先使用int my_count = 0


在提供的代码中我没有看到 logs_count。你是不是想说 my_count - DeepSpace
1
这段代码很好,没有必要在 Python 中在循环外部初始化 my_count - Chris_Rands
2个回答

140

with语句不会创建作用域(与ifforwhile一样不会创建作用域)。

因此,Python会分析代码并看到您在with语句中进行了赋值,因此这将使变量成为局部变量(在实际作用域内)。

在Python中,变量不需要在所有代码路径中进行初始化:作为程序员,您负责确保在使用变量之前对其进行了赋值。这可以使代码更短:例如,假设您确定列表至少包含一个元素,则可以在for循环中对其进行赋值。在Java中,在for循环中进行赋值被认为是不安全的(因为可能永远不会执行循环体)。

with语句作用域之前进行初始化可能更加安全,因为在with语句之后,我们可以安全地假定该变量存在。另一方面,如果变量应该with语句中进行赋值,则在with语句之前不进行初始化实际上会导致进行额外的检查:如果在with语句中跳过了赋值,Python会报错。

with语句仅用于上下文管理目的。它通过语法强制要求您在缩进结束时关闭在with中打开的上下文。


所以我需要初始化吗?还是像我现在这样在with语句外使用变量my_count?哪种方式更好? - danish sodhi
1
@crystal:我更新了答案并提供了更多关于那个问题的信息。这回答了你的问题吗? - Willem Van Onsem
感谢您的解释 :D - danish sodhi
虽然这感觉很不符合 Python 的规范。我尽量避免在 for 循环中初始化变量之后再使用,而在 if 代码块中赋值的变量总是在 else 代码块中有相似的赋值。try/except 代码块也是如此。虽然对于 with 语句来说不需要这样的安全保障,但它看起来有些“不对劲”。if 语句中的赋值也感觉有点不好,所以我更喜欢条件表达式。不幸的是,with 语句似乎没有类似的东西。 - BlackShift
1
@BlackShift:是的,但对于with语句来说,情况又不同了。由于该语句体将被执行(直到出现异常或结束),因此有时最好尽可能缩短with语句,例如当它打开一个文件时,我们希望尽快关闭该文件。 - Willem Van Onsem
1
@Willem Van Onsem,是的,我真的得训练自己让我的with块变短。通常发生的情况是:1)编写一个带有with语句的函数(大多数情况下是打开文件),2)自动将所有(间接)使用“as”变量的内容放入块中,包括任何返回语句,3)意识到返回语句通常不应该在块中,4)再次取消几乎所有缩进(通常只保留“read”),5)感觉糟糕,因为代码看起来不太好看 :-)。但是没关系。 - BlackShift

8
你还应该阅读PEP-343和Python文档。这将清楚地表明,它不是关于创建范围,而是使用上下文管理器。我引用了Python文档中的上下文管理器。

上下文管理器是一个对象,定义了执行with语句时要建立的运行时上下文。上下文管理器处理进入和退出所需的运行时上下文,以执行代码块。通常使用with语句调用上下文管理器(在“with语句”一节中描述),但也可以通过直接调用其方法来使用。

上下文管理器的典型用途包括保存和恢复各种全局状态,锁定和解锁资源,关闭打开的文件等。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接