我正在为我现在正在编写的程序编写模块管理器,我想将模块名存储在字典中,然后引用它们并从globals()调用它们。
1 2
| module_number = 5
module_names = ["","quiz","scores","gender","help","exit"] |
那我就可以打电话了
1
| globals()[module_names[module_number]]() |
号
它将调用exit()并关闭脚本,相反,我得到结果错误:
Traceback (most recent call last): File"a2.py", line 103, in start() File"a2.py", line 44, in start menu() File"a2.py", line 36, in menu call_module(choice) File"a2.py", line 50, in call_module globals()converter[int(module_number)]
KeyError: 'exit'
号
- python中exit()和sys.exit()的区别
exit不在globals()中,因为它不是全球性的,而是内置的。
在Python中,"全局"名称空间是每个模块的,而不是系统范围的。有一个特殊的"内置"模块,它可以容纳真正系统范围内的内容,比如正常的内置功能和一些特殊的内容,比如exit。
您可以使用import builtins访问此模块。
解释器访问这个模块的方式有点奇怪。全局查找的工作原理大致如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| def get_global(global_namespace, name):
try:
return global_namespace[name]
except KeyError:
pass
try:
builtins = global_namespace['__builtins__']
except KeyError:
raise NameError(name)
if isinstance(builtins, types.ModuleType):
builtins = builtins.__dict__
try:
return builtins[name]
except KeyError:
raise NameError(name) |
在像exec这样的地方有特殊的代码,以及用于构建函数对象的内部代码,这可以确保如果您重写了正常的globals字典,__builtins__就会被复制过来(除非您明确地告诉它不要这样做)。当导入系统从模块源(或编译的.pyc中)构建模块对象时,它调用exec,因此每个模块的全局都以右边的__builtins__结束。
builtins模块中的大多数内容都存在,因为它们是编译成的(正如您从名称中所期望的那样);对于cpython,您可以在Python/bltinmodule.c中看到源代码。
但请注意,exit不在那里。实际上,它是由site模块注入到builtins模块中的,该模块作为正常启动序列的一部分导入(除非禁用)。您可以在Lib/site.py和Lib/_sitebuiltins.py中看到执行此操作的代码。exit常数表示它是这样注入的。
因此,当您在代码中或在交互提示下键入exit时,可以在globals()['__builtins__']['exit']或globals()['__builtins__'].__dict__['exit']中找到它。
但如果您想手动访问它,最好是执行import builtins并将其作为builtins.exit访问。
尽管如此,您还是很少想访问builtins.exit;如果您想以编程方式退出,请调用sys.exit,这是一个正常的函数。builtins.exit是一个特殊的Quitter对象,专门用于交互使用。(它有一个repr,如果您忘记了括号,它会给出一个有用的消息,并提供一些额外的代码,使它能很好地处理空闲状态。)
事实上,exit常量上的文档明确表示它是:
… useful for the interactive interpreter shell and should not be used in programs.
号
- -1出口实际上不是内置的。现场注射。如果你运行python -S来禁用站点,你会发现出口不在那里。
- @它在江户十一〔一〕里。它被注射到那里,而不是作为bltinmodule.c的一部分,并没有改变这个事实。但如果你认为我的回答不够长,我可以添加更多的信息…
- "它是一个内置的"是误导或掩饰-这是一个由站点修补的Quitter实例。有点不同于作为一个内置的IMO。
- @我觉得这根本没有误导性。它是builtins中的可调用对象。我已经将它与第一段中的"普通内置函数"区分开来,并解释了它如何不仅仅是一个函数。但是为了让你高兴,我添加了一节关于它是如何在builtins中结束的(至少在cpython和pypy中)。
- @WIM也可以这样说,例如,SyntaxError不是内置的,因为在python 3中,内置异常被注入builtin,而不是编译到模块中?
- 不完全是这样,它们被记录为"内置异常",据我所知,不绑定它们就无法导入内置模块。exit和copyright等只是记录为"由站点模块添加的常量"。还有其他模块也有monkeypatch内置模块(例如ipython添加/修改一些名称),或者您可以在EDOCX1中自己修补(10)——它不会将这些对象提升到"它是内置的"状态,因为内置模块的名称空间是可写的。