为什么一个__import__语句会影响下一个语句的有效性?

Rob*_*tts 8 python python-import python-2.7

我正在查看一些带有两个__import__语句的代码,第二个__import__语句不起作用,除非第一个语句已经运行.

目录结构如下:

dir1
 |-__init__.py
 |-subdir1
 |  |-__init__.py
 |  |-file1.py
 |  |-file2.py
 |
 |-subdir2
    |-__init__.py
    |-file1.py
    |-file2.py
Run Code Online (Sandbox Code Playgroud)

代码有两个__import__声明:

m = __import__('dir1.'+subdir1, fromlist=[file1])
...
m = __import__(file2, fromlist=[class_inside_file2])
Run Code Online (Sandbox Code Playgroud)

第一个是有道理的 - 它大致相当于做

from dir1.subdir1 import file1
Run Code Online (Sandbox Code Playgroud)

但允许动态提供子目录和文件.这是第二个声明,我不明白它为何起作用.它看起来应该相当于

from file2 import class_inside_file2
Run Code Online (Sandbox Code Playgroud)

这不应该作为工作file2.pysubdir1,但我的当前工作目录是上面两个层次.此外,所有__init__.py文件都是空的.

正如您所料,第二个import语句失败,ImportError如果它自己运行.但是,在第一个import语句运行后,第二个工作正常.为什么?

Rob*_*tts 5

事实证明,解释相当愚蠢.file1修改sys.path以添加subdir1到路径.随着subdir1道路上,它可以明显发现file2直接,而无需指定任何包.

故事的道德 - 副作用(比如导入模块时发生的事情)是愚蠢的,因为它经常会导致看似奇怪且难以诊断的问题.


Pet*_*son 4

这不仅仅是 __import__ 语句,因为我无法复制这种行为。

$ mkdir -p dir1/subdir1 dir1/subdir2
$ touch dir1/__init__.py dir1/subdir1/__init__.py dir1/subdir2/__init__.py
$ echo "print '1.1'" > dir1/subdir1/file1.py
$ echo "print '1.2'" > dir1/subdir1/file2.py
$ echo "print '2.2'" > dir1/subdir2/file2.py
$ echo "print '2.1'" > dir1/subdir2/file1.py
Run Code Online (Sandbox Code Playgroud)

给出以下结构:

$ find . -name "*.py"
./dir1/__init__.py
./dir1/subdir1/__init__.py
./dir1/subdir1/file1.py
./dir1/subdir1/file2.py
./dir1/subdir2/__init__.py
./dir1/subdir2/file1.py
./dir1/subdir2/file2.py
Run Code Online (Sandbox Code Playgroud)

但是,您发布的第二个 __import__ 命令按预期失败:

$ python
Python 2.7.6 (default, Nov 18 2013, 11:23:24)
[GCC 4.2.1 Compatible Apple LLVM 4.2 (clang-425.0.24)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> subdir1 = 'subdir1'
>>> file1 = 'file1'
>>> m = __import__('dir1.'+subdir1, fromlist=[file1])
1.1
>>> file2 = 'file2'
>>> class_inside_file2 = '*'
>>> m = __import__(file2, fromlist=[class_inside_file2])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named file2
Run Code Online (Sandbox Code Playgroud)

  • @PeterGibson 认为这个问题是第一次导入的副作用,我想说这实际上是一个非常相关的答案。 (4认同)
  • 这不是一个答案。对这个问题的评论,只说你的第一句话,会更好。 (3认同)
  • @BrenBarn我考虑过这一点,但这允许其他人也尝试它(例如在不同的平台上),并在出现错误时纠正我的过程。为什么您认为信息越少越好? (2认同)