【问题标题】:Further confusion with imports in Python与 Python 中的导入进一步混淆
【发布时间】:2016-06-17 23:22:40
【问题描述】:

据我所知,当其中一个模块未导入时,我不明白为什么以下运行 (Python 2.7)

# \sound\formats\script.py
import formats.wavread

print formats.wavread.foo()
print formats.wavwrite.boo()

我的目录结构是

sound\
    __init__.py
    formats\
       __init__.py
        script.py
        wavread.py
        wavwrite.py

__init__.py 都是空的。其余的代码如下

# \sound\formats\wavread.py
import wavwrite # <-- unused import

def foo():
    return "read foo"


# \sound\formats\wavwrite.py
def boo():
    return "write boo"

script.py 运行良好,尽管在我的理解中模块wavwrite.py 没有被导入。然而,我猜想它是在执行import formats.wavread 语句时以某种方式导入的,因为wavread.py 模块中有一个import wavwrite 行。我的印象是这个导入 import wavwrite 完全没用,但它会绑定到 wavread 模块的全局命名空间。因此wavwrite.boo() 方法将超出范围并且无法从script.py 内部访问。显然它不是那样工作的。

script.py 模块的代码中删除子包前缀看起来可以使程序按我的预期工作。因此,如果您运行以下命令

#\sound\formats\script.py
import wavread

print wavread.foo()
print wavwrite.boo()

将通过打印出 read foo 来执行 wavread.foo() 方法,并在下一行遇到错误,它会丢弃消息 NameError: name 'wavwrite' is not defined,因为正如预期的那样,wavwrite 模块尚未导入。

请问这里到底发生了什么以及import formats.wavreadimport wavread 有何不同?

【问题讨论】:

    标签: python import namespaces


    【解决方案1】:

    import wavread 的简单案例是有效的,因为您的脚本与 wavread.py 位于同一目录中,因此它只导入该文件。如果您的脚本位于不同的目录中,它将无法找到 wavread.py

    下一个案例,让我们看看我们能解决什么问题。您的目录结构类似于Python module tutorial 中的目录结构,所以让我们使用那里提到的dir() 内置,它将向您显示范围的内容。例如:

    >>> import formats.wavread
    >>> dir()
    ['__builtins__', '__doc__', '__name__', '__package__', 'formats']
    
    # ... new session
    
    >>> from formats import wavread
    >>> dir()
    ['__builtins__', '__doc__', '__name__', '__package__', 'wavread']
    

    所以我们可以看到import formats.wavread 也导入了父命名空间,因为我们在那里有formats。在第二个示例中,我们只加载了一个特定的子模块,因此它会直接添加到我们的命名空间,而不是 formats。对此的快速测试是将打印语句添加到 formats/__init__.py - 然后运行 ​​import formats.wavread 时,它将被打印出来:

    $ cat formats/__init__.py
    print("formats __init__.py")
    $ python -m formats.wavread -c ""
    formats __init__.py
    

    由于formats被导入,formats.wavwriteformats.wavread都可用。

    现在,我正在解决这个问题,所以我无法告诉你为什么要这样设计,这只是我从可用工具中可以看出的。

    【讨论】:

      【解决方案2】:

      在导入子模块的时候,也会得到子模块的父模块。

      简单示例:

      >>> numpy
      NameError: name 'numpy' is not defined
      >>> import numpy.random
      >>> numpy
      <module 'numpy' from '...\numpy\__init__.pyc'>
      

      【讨论】:

        猜你喜欢
        • 2022-01-17
        • 2013-08-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多