为什么在函数中使用“from ... import *”是不允许的?

9

根据文档所述:

通配符形式的导入语句 from module import * 仅允许在模块层级使用,在类或函数定义中使用将会引发 SyntaxError

为什么?避免在函数中使用它有何意义?有什么问题吗?

1个回答

10
CPython实现在本地变量方面使用了一种特殊的优化:它们不像全局变量那样在运行时从字典中动态查找,而是在编译时静态分配索引,并在运行时通过索引查找,这样速度更快。这要求Python编译器能够在编译时识别所有本地名称,如果在函数级别上有通配符导入,则这是不可能的。
在Python 2中,仍然存在一个回退机制,用于在不能始终静态确定所有本地名称的情况下调用。该机制使用了动态字典来存储本地变量,显著减慢了执行速度。
例如,以下代码:
def f():
    exec "x = 2"
    print x

在Python 2中按预期工作,而

def f():
    exec("x = 2")
    print(x)

在 Python 3 中会导致 NameError 错误。


所以如果我理解正确:在编译时,对于局部作用域,Python会定位并存储所有使用的变量;而对于全局变量,Python会在运行时修改包含所有全局名称的字典。在函数中,我们不能使用通配符,因为Python使用静态机制,它需要找到并编译函数中导入的所有模块以及那些导入在这些模块中的模块。是这样吗? - zer0uno
@antox:是的,没错。由于全局变量是动态的,它们甚至可以在运行时动态创建,例如通过修改globals()字典或使用exec(),因此静态确定可能被导入的所有名称是完全不可能的。 - Sven Marnach
@sven_marnach 好的,只有一个问题。你说在 Python2 中他们使用了双重机制,第一种是静态的,第二种是动态的备选方案。他们不能将全局变量的行为形式也采用类似的方式吗?因为我理解 'statically' 会优化程序,所以他们使用了静态策略,但是如果你想要执行 exec("x=2") 的话,引擎就会退回到第二个策略上。 - zer0uno
1
我的意思是,减速的动态机制是什么,还是从静态到动态机制的整个过程都会减速? - zer0uno
@antox:在不改变语言语义的情况下实现全局变量可能会很困难。例如,您必须静态检测是否有人调用了“globals()”。此外,对于全局变量来说,这可能会带来较少的收益,因为大多数循环中的变量查找都是针对本地变量的。如果您想微调代码以进行优化,可以将全局变量提升到全局范围内。 - Sven Marnach

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