例如,import math导入的所有函数都在数学模块中,而如果我们编写from math import sqrt,pow,则只导入sqrt(),pow()。
他们的表现和记忆有什么不同吗?
发布于 2018-12-27 17:31:34
例如,
import math导入的所有函数都在数学模块中,而如果我们编写from math import sqrt,pow,则只导入sqrt(),pow()。
比那要复杂一些。
如果我们暂时忽略了math是内置到解释器中的(所以没有什么需要实际加载的),那么无论您执行import math、from math import sqrt, pow还是from math import *,无论如何都会加载整个math模块,并且在导入语句之后,它将出现在sys.modules中。因此,它不像有或多或少的工作要做的加载取决于您如何导入它。
这些构造之间的唯一区别是在导入范围内创建对导入语句中提到的名称的引用。
import math本身可能是最便宜的语句,因为它加载模块并在当前作用域中添加对模块对象的本地引用;它本质上可以归结为
math = __import__('math')但是,每次使用都会花费更大的代价,因为如果math.sin位于全局范围内,则需要两个dict查找(一个LOAD_GLOBAL和一个LOAD_ATTR),或者一个局部变量查找(LOAD_FAST) +一个dict查找(LOAD_ATTR) (如果它是在本地导入一个函数)才能真正到达要调用的函数对象。
from math import sqrt, pow将花费更多的钱,因为它需要加载模块,在其中查找sqrt和pow (两个dict查找),并在导入它们的作用域中创建相应的条目(在全局范围中需要两个dict赋值,在函数范围中需要创建两个STORE_FAST本地赋值)。它相当于:
__temp = __import__('math')
sqrt = __temp.sqrt
pow = __temp.pow
del __temp(__temp实际上并不存在,它只是堆栈上的一个对象;sqrt和pow将是局部变量或全局值,这取决于import语句的发布位置)
另一方面,与上述两种方法相比,查找速度更快,因为它只需要一个dict查找(全局导入的LOAD_GLOBAL)或一个本地查找(导入本地到一个函数的LOAD_FAST)。
from math import *与上面相同,但对于模块__all__列表中提供的所有符号(如果没有指定__all__,则由模块周期提供的所有符号)。
从内存的角度来看,后两者的成本要高于前者,因为它们在局部变量列表或全局数据库中创建了更多的条目。
尽管如此,这种考虑通常是完全不相关的,因为我们谈论的是非常小的差异;在决定如何导入时,最重要的是以更少的类型/不那么显式的导入的名义允许对您的命名空间造成多大的污染。
相反,这些问题的优化通常是将频繁调用的函数绑定到局部变量,以避免在内部循环中连续查找;例如
import math
def plot_it(framebuffer):
sin = math.sin
cos = math.cos
for y in range(1024):
for x in range(1024):
framebuffer[y][x] = int(127*(sin(x)+cos(2*y)))通常比在每个迭代中执行math.sin和math.cos要快,甚至比在文件的顶层导入sin和cos并直接在循环中使用它们要快,因为它们分别是两个或一个dict查找(在每个迭代中执行),而在这里,解释器只需要在内部循环中加载两个局部变量(非常快,这只是一个直线数组加载)。
https://stackoverflow.com/questions/53948404
复制相似问题