我认为我从根本上不了解Python如何完成变量范围和名称解析之类的事情。尤其是下面的broken()
函数不起作用的事实确实让我感到惊讶。而且,尽管我在网上闲逛了一段时间以寻找有用的解释,但我仍然不明白。任何人都可以解释或链接到有关这些内容在Python中如何工作的良好描述,并提供足够的详细信息,这样看来在阅读相关材料后broken()
不起作用的原因显而易见。
# Why does this code work fine
def okay0():
def foo():
L = []
def bar():
L.append(5)
bar()
return L
foo()
# and so does this
def okay1():
def foo():
def bar():
L.append(5)
L = []
bar()
return L
foo()
# but the following code raises an exception?
def broken():
def foo():
L = []
bar()
return L
def bar():
L.append(5)
foo()
# Example
test_list = [okay0, okay1, broken]
for test_function in test_list:
try:
test_function()
except:
print("broken")
else:
print("okay")
参考方案
在另一个函数中定义的一个函数可以访问其父级的作用域。
在您的特定情况下,总是在L
中定义foo()
。在前两个示例中,在bar()
中也定义了foo()
,因此它可以按照上述规则访问L
(即,foo()
是bar()
的父级)。
但是,在broken()
上,bar()
和foo()
是同级。他们对彼此的范围一无所知,因此bar()
无法看到L
。
从documentation:
尽管范围是静态确定的,但它们是动态使用的。在执行期间的任何时候,至少有三个嵌套作用域可以直接访问其名称空间:
最里面的作用域(首先搜索)包含本地名称
从最接近的封闭范围开始搜索的任何封闭函数的范围都包含非本地名称,但也包含非全局名称
倒数第二个范围包含当前模块的全局名称
最外面的作用域(最后搜索)是包含内置名称的名称空间
现在,如果okay1
是在L
之后通过文本定义的,为什么bar()
可以工作?
Python在必须实际运行代码之前不会尝试解析标识符(动态绑定,如@Giusti的答案所述)。
当Python执行该函数时,它将看到一个标识符L
并在本地名称空间中寻找它。在cpython实现中,它是一个实际的字典,因此它将在字典中查找名为L
的键。
如果找不到它,它将检查任何封闭函数的作用域,即代表该封闭函数的本地名称空间的其他字典。
请注意,即使在L
之后定义了bar()
,当调用bar()
时,也已经定义了L
。因此,当执行bar()
时,L
已存在于foo()
的本地名称空间中,当Python在L
中看不到bar()
时,将搜索该名称空间。
文档的支持部分:
名称空间是从名称到对象的映射。目前,大多数名称空间都是作为Python字典实现的,但通常不会以任何方式引起注意(性能除外),并且将来可能会发生变化。
(...)
函数的本地名称空间是在调用函数时创建的,并在函数返回或引发函数中未处理的异常时删除。 (实际上,忘记是描述实际情况的更好方法。)当然,递归调用每个都有自己的本地名称空间。
作用域是可直接访问名称空间的Python程序的文本区域。这里的“直接访问”是指对名称的不合格引用试图在名称空间中找到该名称。
Python exchangelib在子文件夹中读取邮件 - python我想从Outlook邮箱的子文件夹中读取邮件。Inbox ├──myfolder 我可以使用account.inbox.all()阅读收件箱,但我想阅读myfolder中的邮件我尝试了此页面folder部分中的内容,但无法正确完成https://pypi.python.org/pypi/exchangelib/ 参考方案 您需要首先掌握Folder的myfo…
python-docx应该在空单元格已满时返回空单元格 - python我试图遍历文档中的所有表并从中提取文本。作为中间步骤,我只是尝试将文本打印到控制台。我在类似的帖子中已经看过scanny提供的其他代码,但是由于某种原因,它并没有提供我正在解析的文档的预期输出可以在https://www.ontario.ca/laws/regulation/140300中找到该文档from docx import Document from…
Python GPU资源利用 - python我有一个Python脚本在某些深度学习模型上运行推理。有什么办法可以找出GPU资源的利用率水平?例如,使用着色器,float16乘法器等。我似乎在网上找不到太多有关这些GPU资源的文档。谢谢! 参考方案 您可以尝试在像Renderdoc这样的GPU分析器中运行pyxthon应用程序。它将分析您的跑步情况。您将能够获得有关已使用资源,已用缓冲区,不同渲染状态上…
Python sqlite3数据库已锁定 - python我在Windows上使用Python 3和sqlite3。我正在开发一个使用数据库存储联系人的小型应用程序。我注意到,如果应用程序被强制关闭(通过错误或通过任务管理器结束),则会收到sqlite3错误(sqlite3.OperationalError:数据库已锁定)。我想这是因为在应用程序关闭之前,我没有正确关闭数据库连接。我已经试过了: connectio…
python:ConfigParser对象,然后再阅读一次 - python场景:我有一个配置文件,其中包含要执行的自动化测试的列表。这些测试是长期循环执行的。 配置文件的设计方式使ConfigParser可以读取它。由于有两个三个参数,因此我需要通过每个测试。现在,此配置文件由script(s1)调用,并且按照配置文件中的列表执行测试。Script(s1)第一次读取配置,并且在每次测试完成后都会执行。阅读两次的要求:由于可能会…