包: 把解决一类问题的模块放在一个文件夹里
如果文件夹中有__init__.py文件就说明该文件夹是个包(2.0+必须有.__int__.py文件,3.0+可以没有)
# 创建目录
import os
os.makedirs('package/p1')
os.makedirs('package/p2')
os.makedirs('package/p3')
l = []
l.append(open('package/__init__.py', 'w'))
l.append(open('package/p1/__init__.py', 'w'))
l.append(open('package/p1/p1_1.py', 'w'))
l.append(open('package/p1/p1_2.py', 'w'))
l.append(open('package/p2/__init__.py', 'w'))
l.append(open('package/p2/p2_1.py', 'w'))
l.append(open('package/p3/__init__.py', 'w'))
l.append(open('package/p3/p3_1.py', 'w'))
map(lambda f: f.close(), l)
# 目录结构
├── package # 包
│ ├── __init__.py
│ ├── p1
│ │ ├── __init__.py
│ │ ├── p1_1.py # p1_get1()
│ │ └── p1_2.py # p1_get2()
│ ├── p2
│ │ ├── __init__.py
│ │ └── p2_1.py # p2_get1()
│ └── p3
│ │ ├── __init__.py
│ │ └── p3_1.py # p3_get1()

# 总体的目录结构
├── package_project
│ ├── package # 包
│ │ ├── __init__.py
│ │ ├── p1
│ │ │ ├── __init__.py
│ │ │ ├── p1_1.py # p1_get1()
│ │ │ └── p1_2.py # p1_get2()
│ │ ├── p2
│ │ │ ├── __init__.py
│ │ │ └── p2_1.py # p3_get1()
│ │ └── p3
│ │ ├── __init__.py
│ │ └── p3_1.py # p3_get1()
│ └── package_file.py # 引入包的脚本文件

1. 引入包
- import
import package.p1.p1_1
package.p1.p1_1.p1_get1() # 使用 p1_1.py 下的 p1_get1() 方法
- import as
import package.p1.p1_1 as alias_p1_1
alias_p1_1.p1_get1()
- from …… import ……
from package.p1 import p1_1
p1_1.p1_get1()
# 错误示范
from package.p1 import p1_1.p1_get1
p1_get1()
2. __init__.py
不管是哪种方式,只要是第一次导入包或者是包的任何其他部分,都会依次执行包下的__init__.py文件(我们可以在每个包的文件内都打印一行内容来验证一下),这个文件可以为空,但是也可以存放一些初始化包的代码(类似于绝对)。
3.单独导入包
- 单独引入包时不会引入包中所有包含的所有子模块
- 单独引入包且直接执行包下的模块的方法的时候就会报错,因为当引入包的时候它就会像引入模块一样执行里面的 .py 文件即 __init__.py 且这时里面并没有引入任何模块就会报错 -> 使用 绝对引入 或 相对引入解决
# package_file.py
import package
package.p1.p1_1.p1_get1()
'''
执行结果 报错
Traceback (most recent call last):
File "C:/Users/Yeung/PycharmProjects/package_project/package_file.py", line 18, in <module>
package.p1.p1_1.p1_get1()
AttributeError: module 'package' has no attribute 'p1'
'''
4. 绝对引入
- 注意: 当包中的模块需要引入其他模块的时候需要使用绝对引入且可以单独运行该文件
# 绝对引入
├── package # 包
│ ├── __init__.py # import package.p1
# import package.p2
# import package.p3
│ ├── p1
│ │ ├── __init__.py # import package.p1.p1_1
# import package.p1.p1_2
│ │ ├── p1_1.py
│ │ └── p1_2.py
│ ├── p2
│ │ ├── __init__.py # import package.p2.p2_1
│ │ └── p2_1.py
│ └── p3
│ │ ├── __init__.py # import package.p3.p3_1
│ │ └── p3_1.py
# package_file.py
import package
package.p1.p1_1.p1_get1()
# package/__init__.py
# 写法一
import package.p1
import package.p2
import package.p3
# 写法二
from package import p1
from package import p2
from package import p3
# package/p1/__init__.py
import sys
print(sys.path) # 当 package_file.py 执行的时候 sys.path 的返回值 ['C:\\Users\\Yeung\\PycharmProjects\\package_project', ……]
# 需要从 package 开始导入,因为当 package_file.py 执行的时候 sys.path 是从 package_project 开始找起的且 p1 不在 package_project 的根目录下,所以才从 package 开始导入 -> day21 包的初识 00:40:19
# 写法一
import package.p1.p1_1
import package.p1.p1_2
# 写法二
from package.p1 import p1_1
from package.p1 import p1_2
# package/p2/__init__.py
# 写法一
import package.p2.p2_1
# 写法二
from package.p2 import p2_1
# package/p3/__init__.py
# 写法一
import package.p3.p3_1
# 写法二
from package.p3 import p3_1
5. 相对引入
- 注意: 当包中的模块需要引入其他模块的时候需要使用相对引入且不能单独运行该文件会报错的,需要运行使用该包的文件就可以看到效果,绝对引入没有该问题
- . 代表当前目录
- .. 代表上一级目录
# 相对引入
├── package # 包
│ ├── __init__.py # from . import p1
# from . import p2
# from . import p3
│ ├── p1
│ │ ├── __init__.py # from . import p1_1
# from . import p1_2
│ │ ├── p1_1.py
│ │ └── p1_2.py
│ ├── p2
│ │ ├── __init__.py # from . import p2_1
│ │ └── p2_1.py
│ └── p3
│ │ ├── __init__.py # from . import p3_1 引入当前目录下的 p3_1.py 模块
│ │ └── p3_1.py # from ..p2 import p2_1 使用上一级目录下的 p2 文件夹下的 p2_1.py 模块,且不能单独运行 p3_1.py 文件会报错的,需要运行 package_file.py 才能看到结果
# package_file.py
import package
package.p1.p1_1.p1_get1()
# package/__init__.py
from . import p1
from . import p2
from . import p3
# package/p1/__init__.py
from . import p1_1
from . import p1_2
# package/p2/__init__.py
from . import p2_1
# package/p3/__init__.py
from . import p3_1
6. 相对引入 from …… import *
- 用法一
# 绝对引入
├── package # 包
│ ├── __init__.py
│ ├── p1
│ │ ├── __init__.py # __all__ = ['p1_1','p1_2']
│ │ ├── p1_1.py
│ │ └── p1_2.py
│ ├── p2
│ │ ├── __init__.py # __all__ = ['p2_1']
│ │ └── p2_1.py
│ └── p3
│ │ ├── __init__.py # __all__ = ['p3_1']
│ │ └── p3_1.py
# package_file.py
from package.p1 import *
from package.p2 import *
from package.p3 import *
p1_1.p1_get1()
p1_2.p1_get2()
p2_1.p2_get1()
p3_1.p3_get1()
# package/__init__.py
# package/p1/__init__.py
__all__ = ['p1_1','p1_2']
# package/p2/__init__.py
__all__ = ['p2_1']
# package/p3/__init__.py
__all__ = ['p3_1']
- 用法二
# 相对引入
├── package # 包
│ ├── __init__.py # from .p1 import *
# from .p2 import *
# from .p3 import *
│ ├── p1
│ │ ├── __init__.py # __all__ = ['p1_1','p1_2']
│ │ ├── p1_1.py
│ │ └── p1_2.py
│ ├── p2
│ │ ├── __init__.py # __all__ = ['p2_1']
│ │ └── p2_1.py
│ └── p3
│ │ ├── __init__.py # __all__ = ['p3_1']
│ │ └── p3_1.py
# package_file.py
import package
package.p1_1.p1_get1()
package.p1_2.p1_get2()
package.p2_1.p2_get1()
package.p3_1.p3_get1()
# package/__init__.py
from .p1 import *
from .p2 import *
from .p3 import * # 引入当前目录下的 p3_1.py 模块中的所有内容
# package/p1/__init__.py
__all__ = ['p1_1','p1_2']
# package/p2/__init__.py
__all__ = ['p2_1']
# package/p3/__init__.py
__all__ = ['p3_1']