我有两个文件说a.py
和b.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
答案 0 :(得分:5)
在python中,所有模块都有自己的全局命名空间,并且创建了包含所有内置名称的命名空间,并且模块不与其他仅内置命名空间共享它是常见的,并且可用于所有模块,你导入一个它添加到模块全局命名空间的模块,而不是导入到构建的命名空间
import语句有两件事:
一,如果请求的模块尚不存在,则执行导入文件中的代码
两个使它可用作模块。后续导入语句将跳过第一步。
,重点是模块中的代码只执行一次,无论从其他各个模块导入多少次。
答案 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是有效的。
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)))
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
将import math
放入b.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()))
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版:
在此版本中,我们修改a.py
,如下所示(b.py
保持与版本2中相同):
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
最后,让我们通过将a
中的所有内容导入b
并继续导入从b
到a
的所有内容来修复版本1:
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)))
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
来修复代码。您无法将包xxx
和b
导入a
,并希望b
能够神奇地了解xxx
。例如,b
将a
导入b
后就不知道a
,就像math
无法确定它已被导入a
一样math
导入a
时,{(1}})无法“了解”其他包导入a
的内容。
顺便说一下,您可以通过切换math
中的导入顺序,轻松地再次破坏固定版本1b:
a.py
答案 3 :(得分:1)
根据我在my previous answer中的实验以及来自How to get a reference to current module's attributes in Python的一些信息,我提出了一个解决方案,实际上可以解决您的导入问题。 所有更改专门到文件a.py
,并且未触及b.py
。
# 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']
# 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']
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))
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.