引子
考虑有如下代码结构
.
├── cat
│ ├── __init__.py
│ ├── cat.py
│ └── moo.py
└── dog
├── __init__.py
└── dog.py
2 directories, 5 files
情况1:
# ./cat/cat.py
import moo
其余文件为空。如果我们用运行命令:
python cat/cat.py
,则程序正常运行;如果运行命令;
python -m cat.cat
,则会报错;
情况2:
# ./cat/cat.py
from . import moo
则运行结果相反。
其实,我们的问题早就有人提出过了。PEP 395
The fact that most methods of invoking Python code from the command line break when that code is inside a package, and the two that do work are highly sensitive to the current working directory is all thoroughly confusing for a beginner. :如果一段代码在一个包内,那么从命令行使用这段代码是非常非常容易出错的,只有2种方法可行:
-
在整个包的外部,
python -c "from module import code
, -
在整个包的外部,通过
-m
参数执行。
如果在包内部,即使你的代码正确,也基本会出错。
分析
情况1:
-
当我们运行
python cat/cat.py
时,这时候系统的搜素路径包括./cat/
,我们可以通过在./cat/cat.py
中添加import sys; print(sys.path)
证实这一点。 -
当我们运行
python -m cat.cat
时,系统的搜索路径只包括.
,也就是当前文件夹,我们可以通过在当前文件夹下添加一个moo.py
文件,这样python -m cat.cat
就不会报错了。可见,这时的搜索空间,不包括自文件夹。
情况2:
情况2其实和情况1很不一样,情况2叫做
package relative import
,也就是包内间接引用。顾名思义,这种引用方法
只能在包内使用
。也就是说,只能通过
python -m cat.cat
, 或者是
python -c "from cat import cat"
之类的方法来使用。以下内容源自
python
官方文档中的 The import statement
When a module or package is contained within another package ... using leading dots in the specified module or package after from you can specify how high to traverse up the current package hierarchy without specifying exact names.
官方文档中的Package Relative Import 展示了详细的用法。
import
python
中,载入一个包有几种方式:
-
import
语句 -
importlib
模块提供的方法 -
内置方法
__import__
(不提倡)
python
中,有
module
,有
package
。
package
都是
module
, 但
module
不一定是
package
。
module
只有一种,
package
有2种。
代码重载:
importlib.reload
使用
importlib.reload
会重载当前代码。
import os
import importlib
import foo
print("foo.a: {}".format(foo.a))
command = 'echo a=2 >> foo.py'
print(command)
os.popen(command)
importlib.reload(foo)
print("foo.a: {}".format(foo.a))
输出:
foo.a: 2
echo a=2 >> foo.py
foo.a: 2
参考资料
import 语法
PEP 395
PEP 420