导入不工作

Import not Working

我有两个文件 a.pyb.py

在 a.py 中, 我们

import xxx
from b import *

在 b.py 中我们有一个需要 module xxx 的函数。 现在,当从 a.py 调用 b.py 中的函数时,它找不到模块 xxx.

为什么会这样?解决方法是什么? 由于某些原因,我无法在 b.py 中执行 import xxx

MCV:

a.py

import xxx
from b import *
fun()

b.py

def fun():
    xxx.dosomething()

错误:

Global name xxx not defined

问题:

a.py:

import numpy
print("a.py is imported")

b.py:

import a
numpy.zeros(8)

结果(python3 b.py):

a.py is imported
Traceback (most recent call last):
  File "b.py", line 3, in <module>
    numpy.zeros(8)
NameError: name 'numpy' is not defined

答案:

我想这更适合编写库。假设a.py是库的一部分,b是使用库的用户程序,库是我写的。如果我在 a.py 中导入的所有内容 (import numpy) 都显示在 b.py 中,我的库的 API 将不会那么干净,因为我无法隐藏 numpy 库来自我图书馆的用户。我想这就是如果 b.py 导入 a.py.

,那么 a.py 中导入的库从 b.py 中隐藏的原因

您可以在 b.py

中导入 xxx

如果其名称与您在 b 中导入的另一个文件冲突,请执行以下操作:

import xxx as some_name

并且在 b.py 中,您现在可以将其称为 some_name,即

some_name.run()

这是一组试图模拟您的问题的两个文件。版本 1 是您所描述的,版本 2 是有效的。

版本 1(OP 问题)

文件'a.py':

print("a.py: entered a.py")
import math
print("a.py: imported math")
print("a.py: 1st dir()={}".format(dir()))
from b import *
print("a.py: imported * from b")
print("a.py: 2nd dir()={}".format(dir()))
def angle(x, y):
    return math.acos(x/mysq(x*x+y*y))
print("a.py: angle has been defined")
print("a.py: 3rd dir()={}".format(dir()))
import b
print("a.py: dir(b)={}".format(dir(b)))

文件'b.py':

print("b.py: entered b.py")
print("b.py: 1st dir():{}".format(dir()))
def mysq(x):
    return math.sqrt(x)
print("b.py: mysq has been defined")        
print("b.py: 2nd dir():{}".format(dir()))
print("b.py: leaving b.py...")

然后

>>> import a
a.py: entered a.py
a.py: imported math
a.py: 1st dir()=['__builtins__', '__cached__', '__doc__', '__file__',
                 '__loader__', '__name__', '__package__', '__spec__',
                 'math']
b.py: entered b.py
b.py: 1st dir():['__builtins__', '__cached__', '__doc__', '__file__',
                 '__loader__', '__name__', '__package__', '__spec__']
b.py: mysq has been defined
b.py: 2nd dir():['__builtins__', '__cached__', '__doc__', '__file__',
                 '__loader__', '__name__', '__package__', '__spec__',
                 'mysq'] # <-- NOTICE that module 'b' is still hasn't
                         # loaded 'math' before leaving it!!!
b.py: leaving b.py...
a.py: imported * from b
a.py: 2nd dir()=['__builtins__', '__cached__', '__doc__', '__file__',
                 '__loader__', '__name__', '__package__', '__spec__',
                 'math', 'mysq']
a.py: angle has been defined
a.py: 3rd dir()=['__builtins__', '__cached__', '__doc__', '__file__',
                 '__loader__', '__name__', '__package__', '__spec__',
                 'angle', 'math', 'mysq']
a.py: dir(b)=['__builtins__', '__cached__', '__doc__', '__file__',
              '__loader__', '__name__', '__package__', '__spec__',
              'mysq'] # <-- NOTICE that module 'b' is still not aware of 'math'!!!
>>> a.angle(7,8)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/.../a.py", line 9, in angle
    return math.acos(x/mysq(x*x+y*y))
  File "/Users/.../b.py", line 4, in mysq
    return math.sqrt(x)
NameError: name 'math' is not defined

版本 2(工作)

import math 放入 b.py 并将其从 a.py 中删除:

文件'a.py':

from b import *
print("a.py: imported * from b")
print("a.py: 1st dir()={}".format(dir()))
def angle(x, y):
    return math.acos(x/mysq(x*x+y*y))
print("a.py: angle has been defined")
print("a.py: 2nd dir()={}".format(dir()))

文件'b.py':

print("b.py: entered b.py")
import math
print("b.py: loaded math")
print("b.py: 1st dir():{}".format(dir()))
def mysq(x):
    return math.sqrt(x)
print("b.py: mysq has been defined")        
print("b.py: 2nd dir():{}".format(dir()))
print("b.py: leaving b.py...")

然后

>>> import a
b.py: entered b.py
b.py: loaded math
b.py: 1st dir():['__builtins__', '__cached__', '__doc__', '__file__',
                 '__loader__', '__name__', '__package__', '__spec__', 'math']
b.py: mysq has been defined
b.py: 2nd dir():['__builtins__', '__cached__', '__doc__', '__file__',
                 '__loader__', '__name__', '__package__', '__spec__',
                 'math', 'mysq']
b.py: leaving b.py...
a.py: imported * from b
a.py: 1st dir()=['__builtins__', '__cached__', '__doc__', '__file__', 
                 '__loader__', '__name__', '__package__', '__spec__',
                 'math', 'mysq'] # <-- NOTICE 'math' in a.py!!!
a.py: angle has been defined
a.py: 2nd dir()=['__builtins__', '__cached__', '__doc__', '__file__',
                 '__loader__', '__name__', '__package__', '__spec__',
                 'angle', 'math', 'mysq']
>>> a.angle(7,8)
0.8519663271732721

我无法准确解释(表述)这种行为背后的机制,但对我来说似乎是合理的:b.py 中的 mysq() 应该如何了解 math?大量 print 语句的输出表明,在版本 1(OP 问题)中,从 b 导入会导致将 a.py 中 defined/imported 在 [=23] 中的所有内容导入到 a.py 的命名空间中=].整个 b.py 在导入 a.py 时执行一次。但是,b 本身从来没有 "knows" 关于 math.

的任何事情

在版本 2 中,一切都按预期工作,因为 math 被导入 b,它在导入 a 时立即执行,并从 [=29= 导入所有内容](包括math)变成a.

现在,让我们再做一些实验...让我们破解版本 2:

版本 2b(损坏)

在此版本中,我们将 a.py 修改如下(b.py 与版本 2 相同):

文件'a.py':

import b # <-- We do not import 'math' from b into a!
         # Is it still "loaded" somehow into 'a'?
def angle(x, y):
    return math.acos(x/b.mysq(x*x+y*y))

导入 "just" b 本身(与从 b 导入所有内容 相反)不会将 math 导入 a:

>>> a.angle(7,8)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/.../a.py", line 10, in angle
    return math.acos(x/b.mysq(x*x+y*y))
NameError: name 'math' is not defined

版本 1b(固定)

最后,让我们通过将 a 中的所有内容导入 b 以及继续将 b 中的所有内容导入 a 来修复版本 1:

文件'a.py':

print("a.py: entered a.py")
import math
print("a.py: imported math")
print("a.py: 1st dir()={}".format(dir()))
from b import *
print("a.py: imported * from b")
print("a.py: 2nd dir()={}".format(dir()))
def angle(x, y):
    return math.acos(x/mysq(x*x+y*y))
print("a.py: angle has been defined")
print("a.py: 3rd dir()={}".format(dir()))
import b # extra check of b
print("a.py: dir(b)={}".format(dir(b)))

文件'b.py':

print("b.py: entered b.py")
print("b.py: 1st dir():{}".format(dir()))
from a import *
print("b.py: imported * from a")
print("b.py: 2nd dir():{}".format(dir()))
def mysq(x):
    return math.sqrt(x)
print("b.py: mysq has been defined")        
print("b.py: 3rd dir():{}".format(dir()))
print("b.py: leaving b.py...")

然后

>>> import a
a.py: entered a.py
a.py: imported math
a.py: 1st dir()=['__builtins__', '__cached__', '__doc__', '__file__',
                 '__loader__', '__name__', '__package__', '__spec__',
                 'math'] # 'math' is loaded first into 'a'
b.py: entered b.py
b.py: 1st dir():['__builtins__', '__cached__', '__doc__', '__file__',
                 '__loader__', '__name__', '__package__', '__spec__'
                ] # 'b' doesn't "know" yet about 'math'
b.py: imported * from a
b.py: 2nd dir():['__builtins__', '__cached__', '__doc__', '__file__', 
                 '__loader__', '__name__', '__package__', '__spec__', 
                 'math'] # after importing *(!!!) from 'a' into 'b', 'b' now has 'math' 
b.py: mysq has been defined
b.py: 3rd dir():['__builtins__', '__cached__', '__doc__', '__file__', 
                 '__loader__', '__name__', '__package__', '__spec__', 
                 'math', 'mysq']
b.py: leaving b.py...
a.py: imported * from b
a.py: 2nd dir()=['__builtins__', '__cached__', '__doc__', '__file__', 
                 '__loader__', '__name__', '__package__', '__spec__', 
                 'math', 'mysq'] # NOTICE: math is not imported twice into 'a'
a.py: angle has been defined
a.py: 3rd dir()=['__builtins__', '__cached__', '__doc__', '__file__', 
                 '__loader__', '__name__', '__package__', '__spec__', 
                 'angle', 'math', 'mysq']
a.py: dir(b)=['__builtins__', '__cached__', '__doc__', '__file__',
              '__loader__', '__name__', '__package__', '__spec__',
              'math', 'mysq'] # just to make sure, check that 'b' still has 'math' defined.
>>> a.angle(7,8)
0.8519663271732721

因此,您可以通过将 *a 导入 b 以及从 b 导入 a 来修复您的代码。您不能将包 xxxb 导入 a 并期望 b 神奇地了解 xxx。例如,当 b 被导入 a 时,b 不知道 a,就像 math 不知道它被导入 a ] 并且它 (math) 无法 "learn" 当 a 导入 math.

时还有哪些其他包被导入 a

顺便说一句,您可以通过切换 a.py 中的导入顺序轻松再次破解固定版本 1b:

文件'a.py':

from b import * # swap order of imports breaks Version 1b!
import math

在python中,所有模块都有自己的全局命名空间,并且创建了一个包含所有内置名称的命名空间,并且模块不与其他仅内置的命名空间共享,并且可用于所有模块,当您导入一个模块时,它会添加到模块全局命名空间中,而不是内置命名空间中

导入语句做了两件事:

一、如果请求的模块还不存在,则执行导入文件中的代码

two 使它可以作为一个模块使用。后续导入语句将跳过第一步。

要点是模块中的代码将只执行一次,无论它从其他各种模块导入多少次。

SOURCE

a.py:

import numpy as np_patched
def f():
    print("patched")
np_patched.array = f

b.py

import a as np_patched
import numpy as np
np.array()

c.py(导入顺序无关紧要?)

import numpy as np
import a as np_patched
np.array()

结果(python3 b.py,或python3 c.py)

patched

解释:

a.py 导入库 X (numpy) 和猴子补丁 X。然后,b.py 导入 a.py。此时,X 对 b.py 不直接可见。在那之后 b.py 导入 X。 Python 不会导入相同的东西两次,所以它继续使用 a.py 中修补的 X 来代替 b.py 而不是导入新的b.py 的 X 副本。这就是为什么 b.py 只得到补丁的 X,而不是原来的 X。

根据我在 and with some information from How to get a reference to current module's attributes in Python 中的实验,我提出了一个实际上可以解决您的导入问题的解决方案。 所有更改都是独占 到文件 a.py 并且 b.py 没有被触及。

解决方案 1:

# in file a.py do this
import xxx
import sys # OR import b (see below)
from b import *
b = sys.modules[fun.__module__] # alternatively, "import b" and drop "import sys" above
# "inject" 'xxx' into 'b':
b.__dict__['xxx'] = globals()['xxx']

解决方案 2:

# in file a.py do this
import xxx
import sys
from b import *
b = sys.modules[fun.__module__] # alternatively, "import b"
# "inject" 'xxx' into 'b':
b.__dict__['xxx'] = sys.modules[__name__].__dict__['xxx']

示例:

文件a.py:

import math # my version of 'xxx'
import sys
from b import *
b = sys.modules[mysq.__module__] # mysq is a function defined in b.py
b.__dict__['math'] = globals()['math']
def angle(x, y):
    return math.acos(x / mysq(x*x + y*y))

文件b.py:

def mysq(x):
    return math.sqrt(x)

运行:

>>> import a
>>> a.angle(7, 8)
0.8519663271732721