导入不起作用

时间:2017-07-20 05:14:07

标签: python python-import

我有两个文件说a.pyb.py

在a.py中, 我们做了

import xxx
from b import *
b.py中的

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

为什么会这样,这里的解决方案是什么? 由于某种原因,我无法import xxx b.py

MCV:

a.py

import xxx
from b import *
fun()

b.py

def fun():
    xxx.dosomething()

错误:

Global name xxx not defined

6 个答案:

答案 0 :(得分:5)

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

enter image description here

import语句有两件事:

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

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

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

SOURCE

答案 1 :(得分:1)

问题:

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中导入的库被隐藏起来的原因。

答案 2 :(得分:1)

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

VERSION 1(OP问题)

file'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)))

file'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中删除:

file'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()))

file'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

我无法解释(制定)这种行为背后的机制,但对我来说似乎是合理的:mysq()中的b.py应该如何知道math?许多print语句的输出表明,在版本1(OP问题)中,从b导入导致导入a.py命名空间的所有内容都在b.py中定义/导入。整个b.py在导入a.py时执行一次。但是,b本身从不“知道”有关math的任何内容。

在版本2中,一切都按预期工作,因为math已导入b,导入a时立即执行,并从b导入所有内容(包括math}到a

现在,让我们做一些实验......让我们打破第2版:

版本2b(已损坏)

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

file'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))

导入“仅”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并继续导入从ba的所有内容来修复版本1:

file'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)))

file'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。例如,ba导入b后就不知道a,就像math无法确定它已被导入a一样math导入a时,{(1}})无法“了解”其他包导入a的内容。

顺便说一下,您可以通过切换math中的导入顺序,轻松地再次破坏固定版本1b:

file'a.py':

a.py

答案 3 :(得分:1)

根据我在my previous answer中的实验以及来自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

答案 4 :(得分:0)

您可以在b.py中导入xxx

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

import xxx as some_name

并且在b.py中你现在可以将它称为some_name,即。,

some_name.run()

答案 5 :(得分:0)

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.此时,对于b.py,X不是直接可见的。在那之后b.py导入X.Python不会导入相同的东西两次,所以它继续并使用a.py中的X修补b.py而不是为b.py导入X的新副本。这就是为什么b.py只能获得修补的X,而不是原始的X.