调用exit()作为全局函数会导致KeyError

时间:2018-08-02 03:55:49

标签: python dictionary

我正在为当前正在编写的程序编写模块管理器,我想将模块名称存储在字典中,然后引用它们并从globals()进行调用。

module_number = 5
module_names  = ["", "quiz", "scores", "gender", "help", "exit"]

然后我希望我可以打电话

globals()[module_names[module_number]]()

哪个会调用exit()并关闭脚本,而是出现错误:

  

回溯(最近一次通话最近):start()中的文件“ a2.py”,第103行,开始菜单中的文件“ a2.py”,第44行,开始menu()文件“ a2.py”,第36行,在菜单中的call_module(choice)文件“ a2.py”,第50行,在call_module globals()converter [int(module_number)]

中      

KeyError:'退出'

1 个答案:

答案 0 :(得分:6)

exit不在globals()中,因为它不是全局变量,而是内置变量。

在Python中,“全局”命名空间是按模块而不是系统范围的。有一个特殊的“内置”模块可以容纳真正在系统范围内的内容,例如the normal builtin functions和一些特殊的东西,例如exit


您可以使用import builtins访问此模块。

解释器访问此模块的方式有点时髦。全局查找大致如下:

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.pyLib/_sitebuiltins.py中查看执行此操作的代码。 exit常量表示它是通过这种方式注入的。


因此,当您在代码中或在交互式提示符下键入exit时,可以在globals()['__builtins__']['exit']globals()['__builtins__'].__dict__['exit']中找到它。

但是,如果要手动访问它,则最好进行import builtins并以builtins.exit的身份访问。

尽管确实如此,但是您仍然很少希望访问builtins.exit;如果要以编程方式退出,请调用sys.exit,这是正常功能。 builtins.exit是特殊的Quitter对象,专门用于交互式使用。 (它有一个repr,如果您忘记了括号,它会提供有用的信息,并提供一些额外的代码使它在IDLE中可以正常使用。)

实际上,exit常量上的文档明确表示它是:

  

...对交互式解释程序外壳很有用,不应在程序中使用。