当外部模块已经导入到其他导入模块中时,是否必须重新导入它们?
Do you have to reimport external modules when they have been already imported in an other imported module?
假设您有两个模块 mod1.py
和 mod2.py
。
在 mod1.py
中你导入一个外部(到你正在写的包)模块,比如 numpy
并且在 mod2.py
中你导入 mod1
:
里面 mod1.py
:
import numpy as np
里面 mod2.py
:
import mod1
现在,如果 mod2
中的一行代码调用 np
,则会引发错误:
NameError: name 'np' is not defined
如何避免在包的每个模块(= 文件)中导入外部模块?
import
可以做两件事:
- 创建模块
- 在绑定到模块的当前作用域中定义一个新变量
一个模块foo
每个进程只会创建一次,无论import foo
执行了多少次。但是,import foo
将 总是 将模块绑定到名称 foo
,即使 foo
已经绑定(到该模块或其他一些值)在当前范围内。
import numpy as np
将名称 np
绑定到 mod1
.
全局范围内的 numpy
模块
import mod1
只绑定名字mod1
;它不会将 mod1
的全局变量带入 mod2
的全局范围。为此,你需要像
这样的东西
from mod1 import np
或者在 mod2
.
中使用 mod1.np
您似乎在寻找一种将 np
放入进程范围的命名空间的方法,可从任何模块访问。 Python 只有一个这样的命名空间,即内置命名空间,但您不能向其添加名称。您只有单独的模块全局命名空间。
上面,我提到了一个模块只创建一次。这是因为 import
将首先检查所请求的模块是否已存在于 sys.modules
中。使用
导入一次后,您可以从任何地方访问np
sys.modules['numpy'] # The "real" name, not the import-defined alias
但是,不能保证 numpy
已经定义了 ,您仍然需要导入 sys
才能访问 sys.modules
,所以这不会比简单地使用
给你带来任何好处
import numpy as np
随心所欲 np
.
这里有两件事需要考虑:导入 模块,以及命名这些导入.
从您的角度来看,这些问题是相同的:如果您想要名称空间中的某些内容,则将其导入:
# mod1.py
import numpy as np
没有其他方法可以将某些内容放入模块的命名空间。 (好吧,没有其他方法不涉及弄乱 sys.modules
来做完全相同的事情)。
但是 python 在这里做了什么?首先,它在 sys.modules
中查找了 numpy
。如果不存在,它会加载 numpy,并将加载的模块插入 sys.modules["numpy"]
。然后它绑定一个本地名称 np
以指向 sys.modules["numpy"]
。因此,如果您导入 mod1
,您可以访问它的导入:
#mod2.py
import mod1
mod1.np
(另外:严格执行命名空间是一个很大的好处,并且使 python 更 更不容易受到随机名称冲突错误的影响。它简化了您作为编码器,因为您不必担心导入模块中的名称会覆盖其他内容,因此您不必求助于命名函数 $get
或其他 'very unlikely' 之类的东西) .
性能
这是否意味着如果多次导入,python将多次加载同一个模块?不会。Python 只会导入一个模块一次:之后它只会绑定一个本地名称以指向 sys.modules
中的模块。所以唯一的性能损失是:
#mod2
import numpy as np
import mod1
np
就是绑定一个名字,这很琐碎(如果你太在意,你就不想使用python)。没有理由这样做:
# mod2.py
from mod1 import np
np
除非更容易不去想你的函数来自哪里(你会经常看到'为了方便,你可以从库y
导入x
,例如导入[=26的组件=] 直接来自 FastApi
).
声明式
像这样管理命名空间有一个巨大的优势:当我阅读您的代码时,我 确切地 知道 function_xyz()
的来源。您要么在作用域中定义它,要么将它导入到该作用域中。将其与例如当我不得不问 JS 或 R 时——xyz 到底从哪里来?然后去查一下。出于同样的原因,如果你写
,大多数 linters 都会对你生气
from numpy import *
并坚持你应该明确地导入你需要的东西。
假设您有两个模块 mod1.py
和 mod2.py
。
在 mod1.py
中你导入一个外部(到你正在写的包)模块,比如 numpy
并且在 mod2.py
中你导入 mod1
:
里面 mod1.py
:
import numpy as np
里面 mod2.py
:
import mod1
现在,如果 mod2
中的一行代码调用 np
,则会引发错误:
NameError: name 'np' is not defined
如何避免在包的每个模块(= 文件)中导入外部模块?
import
可以做两件事:
- 创建模块
- 在绑定到模块的当前作用域中定义一个新变量
一个模块foo
每个进程只会创建一次,无论import foo
执行了多少次。但是,import foo
将 总是 将模块绑定到名称 foo
,即使 foo
已经绑定(到该模块或其他一些值)在当前范围内。
import numpy as np
将名称 np
绑定到 mod1
.
numpy
模块
import mod1
只绑定名字mod1
;它不会将 mod1
的全局变量带入 mod2
的全局范围。为此,你需要像
from mod1 import np
或者在 mod2
.
mod1.np
您似乎在寻找一种将 np
放入进程范围的命名空间的方法,可从任何模块访问。 Python 只有一个这样的命名空间,即内置命名空间,但您不能向其添加名称。您只有单独的模块全局命名空间。
上面,我提到了一个模块只创建一次。这是因为 import
将首先检查所请求的模块是否已存在于 sys.modules
中。使用
np
sys.modules['numpy'] # The "real" name, not the import-defined alias
但是,不能保证 numpy
已经定义了 ,您仍然需要导入 sys
才能访问 sys.modules
,所以这不会比简单地使用
import numpy as np
随心所欲 np
.
这里有两件事需要考虑:导入 模块,以及命名这些导入.
从您的角度来看,这些问题是相同的:如果您想要名称空间中的某些内容,则将其导入:
# mod1.py
import numpy as np
没有其他方法可以将某些内容放入模块的命名空间。 (好吧,没有其他方法不涉及弄乱 sys.modules
来做完全相同的事情)。
但是 python 在这里做了什么?首先,它在 sys.modules
中查找了 numpy
。如果不存在,它会加载 numpy,并将加载的模块插入 sys.modules["numpy"]
。然后它绑定一个本地名称 np
以指向 sys.modules["numpy"]
。因此,如果您导入 mod1
,您可以访问它的导入:
#mod2.py
import mod1
mod1.np
(另外:严格执行命名空间是一个很大的好处,并且使 python 更 更不容易受到随机名称冲突错误的影响。它简化了您作为编码器,因为您不必担心导入模块中的名称会覆盖其他内容,因此您不必求助于命名函数 $get
或其他 'very unlikely' 之类的东西) .
性能
这是否意味着如果多次导入,python将多次加载同一个模块?不会。Python 只会导入一个模块一次:之后它只会绑定一个本地名称以指向 sys.modules
中的模块。所以唯一的性能损失是:
#mod2
import numpy as np
import mod1
np
就是绑定一个名字,这很琐碎(如果你太在意,你就不想使用python)。没有理由这样做:
# mod2.py
from mod1 import np
np
除非更容易不去想你的函数来自哪里(你会经常看到'为了方便,你可以从库y
导入x
,例如导入[=26的组件=] 直接来自 FastApi
).
声明式
像这样管理命名空间有一个巨大的优势:当我阅读您的代码时,我 确切地 知道 function_xyz()
的来源。您要么在作用域中定义它,要么将它导入到该作用域中。将其与例如当我不得不问 JS 或 R 时——xyz 到底从哪里来?然后去查一下。出于同样的原因,如果你写
from numpy import *
并坚持你应该明确地导入你需要的东西。