模块和包
由于在Python中一切皆为对象(Object), 想要好好理解模块和包,一定要先理解命名空间的概念
命名空间(Namespace)
命名空间是变量指向的对象所在的空间范围,命名空间用来隔离相同的变量名
| 命名空间 | 说明 |
|---|---|
| Build-in Namespace | 内建命名空间 |
| Global Namespace | 全局命名空间 |
| Local Namespace | 局部命名空间 |
局部命名空间不光指方法命名空间,还可以是对象命名空间和模块命名空间
比如
Foo.name和Bar.name中name分别位于不同的对象命名空间
模块(Module)
模块是一系列类和方法的集合,表现为一个 py 文件
包(Package)
包是一系列模块的集合,表现为一个包含__init__.py文件的目录
模块的查找
python会先在内建模块中寻找模块,然后才会在sys.path中寻找模块
➜ Downloads python -m site
sys.path = [
'/Users/zhujipeng/Downloads',
'/Library/Python/2.7/site-packages/pip-1.5.6-py2.7.egg',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python27.zip',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac/lib-scriptpackages',
'/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-old',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload',
'/Users/zhujipeng/Library/Python/2.7/lib/python/site-packages',
'/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/PyObjC',
'/Library/Python/2.7/site-packages',
'/Library/Python/2.7/site-packages/PIL',
'/usr/local/lib/wxPython-3.0.2.0/lib/python2.7',
'/usr/local/lib/wxPython-3.0.2.0/lib/python2.7',
]
USER_BASE: '/Users/zhujipeng/Library/Python/2.7' (exists)
USER_SITE: '/Users/zhujipeng/Library/Python/2.7/lib/python/site-packages' (exists)
ENABLE_USER_SITE: True
➜ Downloads python
Python 2.7.10 (default, Jul 14 2015, 19:46:27)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> for i in sys.path:
... print i
...
/Library/Python/2.7/site-packages/pip-1.5.6-py2.7.egg
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python27.zip
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac/lib-scriptpackages
/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-old
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload
/Users/zhujipeng/Library/Python/2.7/lib/python/site-packages
/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/PyObjC
/Library/Python/2.7/site-packages
/Library/Python/2.7/site-packages/PIL
/usr/local/lib/wxPython-3.0.2.0/lib/python2.7
>>> print sys.path[0] == ""
True
sys.path[0]是启动脚本文件所在的目录或者为空表示当前目录
模块的导入
这篇文章写得非常详细,详情参考这里
准备文件
➜ module tree .
.
├── app
│ ├── __init__.py
│ ├── p1
│ │ ├── __init__.py
│ │ ├── core.py
│ │ ├── mp1.py
│ │ └── s1
│ │ ├── __init__.py
│ │ └── ms1.py
│ └── p2
│ ├── __init__.py
│ └── mp2.py
├── main.py
4 directories, 10 files
➜ module cat app/p1/core.py
print 'file is ' + __file__
print 'name is ' + __name__
print 'package is ' + str(__package__)
print
import mp1
import s1.ms1
from ..p2 import mp2
➜ module cat app/p1/mp1.py
print 'file is ' + __file__
print 'name is ' + __name__
print 'package is ' + str(__package__)
print
➜ module cat app/p1/s1/ms1.py
print 'file is ' + __file__
print 'name is ' + __name__
print 'package is ' + str(__package__)
print
➜ module cat app/p2/mp2.py
print 'file is ' + __file__
print 'name is ' + __name__
print 'package is ' + str(__package__)
print
➜ module cat main.py
print 'file is ' + __file__
print 'name is ' + __name__
print 'package is ' + str(__package__)
print
import app.p1.core
文件名由
m和所在包的名字组成
执行文件core.py
➜ module python app/p1/core.py
file is app/p1/core.py
name is __main__
package is None
file is /Users/zhujipeng/PycharmProjects/python-manual/module/app/p1/mp1.pyc
name is mp1
package is None
file is /Users/zhujipeng/PycharmProjects/python-manual/module/app/p1/s1/ms1.pyc
name is s1.ms1
package is None
Traceback (most recent call last):
File "app/p1/core.py", line 8, in <module>
from ..p2 import mp2
ValueError: Attempted relative import in non-package
执行文件
core.py时包的名称是None,此时..p2中的..就找不到参照点所以此时的查找方式是按照
文件查找的方式进行的,参见输出的file值但是此时只会在
app/p1目录和其子目录进行查找,所以找不到mp2.py
执行模块core.py
➜ module python -m app.p1.core
file is /Users/zhujipeng/PycharmProjects/python-manual/module/app/p1/core.py
name is __main__
package is app.p1
file is app/p1/mp1.pyc
name is app.p1.mp1
package is None
file is app/p1/s1/ms1.pyc
name is app.p1.s1.ms1
package is None
file is app/p2/mp2.pyc
name is app.p2.mp2
package is None
执行模块
core.py时包的名称是app.p1,此时..p2中的..指的是包app所以此时的查找方式是按照
模块查找的方式进行的,参见输出的file值
执行文件main.py
➜ module python main.py
file is main.py
name is __main__
package is None
file is /Users/zhujipeng/PycharmProjects/python-manual/module/app/p1/core.pyc
name is app.p1.core
package is None
file is /Users/zhujipeng/PycharmProjects/python-manual/module/app/p1/mp1.pyc
name is app.p1.mp1
package is None
file is /Users/zhujipeng/PycharmProjects/python-manual/module/app/p1/s1/ms1.pyc
name is app.p1.s1.ms1
package is None
file is /Users/zhujipeng/PycharmProjects/python-manual/module/app/p2/mp2.pyc
name is app.p2.mp2
package is None
执行文件
core.py时包的名称是None,此时..p2中的..就找不到参照点所以此时的查找方式是按照
文件查找的方式进行的,参见输出的file值因为此时会在
module目录和其子目录进行查找,所以能够找到mp2.py
参考
如何理解 python 的模块查找原理与方式
深扒Python是如何找到模块的
What sets up sys.path with Python, and when?
Python导入模块的几种姿势
How to do relative imports in Python
Python相对导入机制详解