1

引子

考虑有如下代码结构

.
├── 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种方法可行:
  1. 在整个包的外部,python -c "from module import code
  2. 在整个包的外部,通过-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中,载入一个包有几种方式:

  1. import语句
  2. importlib模块提供的方法
  3. 内置方法__import__ (不提倡)

python中,有module,有packagepackage都是module, 但module不一定是packagemodule只有一种,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


PETCoder亚洲善待程序猿组织
225 声望33 粉丝

Sorry, but I have to leave.-Weibo