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

Jac*_*les 0 python dictionary

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

module_number = 5
module_names  = ["", "quiz", "scores", "gender", "help", "exit"]
Run Code Online (Sandbox Code Playgroud)

我希望我可以打电话

globals()[module_names[module_number]]()
Run Code Online (Sandbox Code Playgroud)

哪个会调用exit()并关闭脚本,而是得到结果错误:

回溯(最近一次调用最后一次):文件"a2.py",第103行,在start()文件"a2.py",第44行,在开始菜单中()文件"a2.py",第36行,在菜单call_module中(选择)文件"a2.py",第50行,在call_module globals()转换器[int(module_number)]中

KeyError:'退出'

aba*_*ert 6

exit不是globals()因为它不是全球性的,所以它是内置的.

在Python中,"全局"命名空间是按模块进行的,而不是系统范围的.有一个特殊的"内置"模块,可以保存真正的系统范围内的东西,比如普通的内置函数和一些特殊的东西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)
Run Code Online (Sandbox Code Playgroud)

在像这样的地方有特殊的代码exec,以及用于构建函数对象的内部代码,这确保了如果覆盖普通globals字典,则会__builtins__被复制(除非您明确告诉它不要).当导入系统从模块源(或编译.pyc)中构建模块对象时,它会调用exec,因此每个模块的全局变量都以右边结束__builtins__.


builtins模块中的大多数东西都在那里,因为它们被编译成它(正如你对名称所期望的那样); 对于CPython,你可以看到源代码Python/bltinmodule.c.

但请注意exit不存在.实际上,它是builtinssite模块注入到模块中的,该模块是作为正常启动序列的一部分导入的(除非您禁用它).您可以在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如果你忘记了括号,它会提供一个有用的信息,还有一些额外的代码可以让它与IDLE一起玩得很好.)

实际上,exit常量上的文档明确地说它是:

...对交互式解释器shell很有用,不应该在程序中使用.