【问题标题】:Import not Working导入不工作
【发布时间】:2017-12-25 14:51:28
【问题描述】:

我有两个文件,分别是 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

【问题讨论】:

  • 不确定您要达到的目标。请提供Minimal, Complete, and Verifiable example。应该不会太难。
  • 你能在b模块中使用import a吗?
  • 你得到什么导入错误?
  • 需要在b.py中导入xxx
  • 也许你应该明确地问一个关于那个的问题。

标签: python python-import


【解决方案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 中导入的库对 b.py 隐藏的原因。

【讨论】:

  • 那太重了...a.py 非常庞大,b.py 只是实用程序...很多人使用...不是一个好主意
  • python 导入东西有点慢。如果计算时间长,那很好。我认为在库中导入 numpy 很好。无论如何,许多 python 程序都使用 numpy。两次导入 numpy 所花费的时间几乎与一次导入 numpy 所用的时间相同。
  • no a.py 有很多我们不想要的东西 b.py .b.py 它只是一个小工具
  • 嗯。 b.py 的启动时间/文件大小很重要吗?如果是这种情况,请为 b.py 创建一个较小的库,使 b.py 成为一个独立程序(不导入 a.py),或者直接用 c/c++ 编写并编译它。
  • python 的 import 和 c/c++ 的 #include 确实不一样。在 C++ 中,如果你在一个标头中#include 某些内容,然后将该标头包含在另一个标头中,则该内容在两个标头中都是可见的,我们需要包含保护。 Python 不需要包含保护,因为如果您在 python 文件 a.py 中导入 numpy,那么 import numpy 将保留在 a.py 中。即使 b.py 导入 a.py,a.py 中的 numpy 也不会出现在 b.py 中。
【解决方案2】:

你可以在b.py中导入xxx

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

import xxx as some_name

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

some_name.run()

【讨论】:

  • 不,这不是名称冲突。它是修补所有套接字的 grequest 和不想要修补套接字的多进程之间的冲突
  • @vks 我没有太多使用 grequests 和多进程的经验,但我认为您的问题更多是抽象?您在 b.py 中的代码可能会写得更好,以便您可以选择使用 grequest 或未修补的套接字进行多进程,而不是将其与 grequest 紧密耦合?
【解决方案3】:

这是一组两个文件,它们试图模拟您的问题。版本 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 导入会导致将b.py 中定义/导入的所有内容导入a.py 的命名空间。整个b.py 在导入a.py 时执行一次。但是,b 本身从不“知道”任何关于 math 的信息。

在版本 2 中,一切都按预期工作,因为 math 被导入到 b,它在导入到 a 时立即执行,并将 b(包括 math)中的所有内容导入到 @987654346 @。

现在,让我们做更多的实验......让我们打破第 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))

导入“只是”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 在将b 导入a 时不知道a,就像math 不知道它已导入a 并且它(math)不能“学习”当a 导入math 时,还导入了哪些其他包到a

对了,你可以通过在a.py中切换导入顺序轻松再次破解固定版本1b:

文件'a.py':

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

【讨论】:

  • import math 不应该出现在b.py
  • @vks 好的,我修复了我的实验以匹配你的情况。
  • 我们在a 的命名空间中有xxx...现在我们从a 的命名空间调用b 的某些函数...您不认为该函数有关于a 的命名空间的信息?
  • @vks 我用大量的print 语句显着扩展了我的示例。它还表明您可以通过将 * 从 A 导入 B 和将 * 从 B 导入 A 来修复代码。
  • @vks 即使你没有投票也没关系,但我很高兴你投票了。谢谢!我只是希望这个练习希望能阐明进口的情况。这对我来说是一个很好的学习。但是,在假设 b.py 是您现在必须处理的遗留代码之前,我无法想象 b.fun() 是如何工作的。
【解决方案4】:

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

import 语句做了两件事:

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

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

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

SOURCE

【讨论】:

  • 这一切的来源是什么
  • 就是这样。比如说,a.py 导入库 X 和猴子补丁 X。然后,b.py 导入 a.py。此时,X 对 b.py 不直接可见。之后 b.py 导入 X。Python 不会两次导入相同的东西,所以它继续使用在 a.py 中修补的 X 用于 b.py,而不是为 b.py 导入 X 的新副本。这就是为什么 b.py 只得到修补的 X,而不是原始的 X。
  • @vks 你不应该接受一个没有努力回答你问题的答案。盲目复制粘贴就等于抄袭,一定要皱眉。
  • @cᴏʟᴅsᴘᴇᴇᴅ 虽然你可能是对的,但我也有一个方面需要考虑,我被困住了,有人让我摆脱了它......所以别无选择,只能接受这个:)
【解决方案5】:

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。

【讨论】:

    【解决方案6】:

    根据我在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
    

    【讨论】:

      猜你喜欢
      • 2017-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-31
      • 2017-05-30
      • 2020-09-20
      • 2018-01-30
      • 2020-09-01
      相关资源
      最近更新 更多