一、什么是包

随着模块数目的增多,把所有模块不加区分地放到一起也是极不合理的,于是Python为我们提供了一种把模块组织到一起的方法,即创建一个包。包就是一个含有init.py文件的文件夹,文件夹内可以组织子模块或子包,例如

pool/                #顶级包
├── __init__.py    
├── futures          #子包
   ├── __init__.py
   ├── process.py
   └── thread.py
└── versions.py      #子模块

需要强调的是

#1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错

#2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模块

接下来我们就以包pool为例来介绍包的使用,包内各文件内容如下

# process.py
class ProcessPoolExecutor:
    def __init__(self,max_workers):
        self.max_workers=max_workers

    def submit(self):
        print('ProcessPool submit')

# thread.py
class ThreadPoolExecutor:
    def __init__(self, max_workers):
        self.max_workers = max_workers

    def submit(self):
        print('ThreadPool submit')

# versions.py
def check():
    print('check versions’)

# __init__.py文件内容均为空

二、包的使用

首次导入包(如import pool)同样会做三件事:

1、执行包下的init.py文件

2、产生一个新的名称空间用于存放init.py执行过程中产生的名字

3、在当前执行文件所在的名称空间中得到一个名字pool,该名字指向init.py的名称空间,例如pool.xxx和pool.yyy中的xxx和yyy都是来自于pool下的init.py,也就是说导入包时并不会导入包下所有的子模块与子包

import pool

pool.versions.check() #抛出异常AttributeError
pool.futures.process.ProcessPoolExecutor(3) #抛出异常AttributeError

pool.versions.check()要求pool下有名字versions,进而pool.versions下有名字check。pool.versions下已经有名字check了,所以问题出在pool下没有名字versions,这就需要在pool下的init.py中导入模块versions

三、绝对导入和相对导入

1、绝对导入:以顶级包为起始

#pool下的__init__.py
from pool import versions

2、相对导入:.代表当前文件所在的目录,..代表当前目录的上一级目录,依此类推

#pool下的__init__.py
from . import versions
pool/                #顶级包
├── __init__.py    
├── futures          #子包
   ├── __init__.py
   ├── process.py
   └── thread.py
└── versions.py      #子模块

同理,针对pool.futures.process.ProcessPoolExecutor(3),则需要

#操作pool下的__init__.py,保证pool.futures
from . import futures #或from pool import futures

#操作futrues下的__init__.py,保证pool.futures.process
from . import process #或from pool.futures import process

例1:

import pool.futures #拿到名字pool.futures指向futures下的__init__.py

pool.futures.xxx #要求futures下的__init__.py中必须有名字xxx

例2:

import pool.futures.thread #拿到名字pool.futures.thread指向thread.py

thread_pool=pool.futures.thread.ThreadPoolExecutor(3)
thread_pool.submit()

相对导入只能用from module import symbol的形式,import ..versions语法是不对的,且symbol只能是一个明确的名字

from pool import futures.process #语法错误
from pool.futures import process #语法正确

针对包内部模块之间的相互导入推荐使用相对导入,需要特别强调:

1、相对导入只能在包内部使用,用相对导入不同目录下的模块是非法的

2、无论是import还是from-import,但凡是在导入时带点的,点的左边必须是包,否则语法错误


posted @ 2020-03-29 17:02  江湖有梦  阅读(135)  评论(0编辑  收藏  举报