07-02 包

一. 包的介绍

# 包: 含有__init__.py文件的文件夹
"""
1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错
2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包的本质就是一种模
"""

# 包下面的__init__.py存在的意义:
"""
当你在运行文件夹的时候,有一个文件可以代替运行。这就是包下的__init__.py文件所存在的一样意义。
"""	

# 包的存在意义:
"""
因为你作为模块的设计者到你的模块越来越多,你要很好的去管理你的功能,你要需要放分文件管理。把你一个一个文件去组织起来。可以把python的一堆模块丢进去,包的用途就是就是被导入的. 其中用来被导入的, 包括包下面所有的东西也包括包自己。有了包这个概念以后你就掌握了一种能够把多个python模块给组织到一个文件夹里面放着的这种解决方案。
"""

# python3中与python2中的__init__.py存在的必要性:
"""
你需要考虑的是,如果下面存放了好多模块,当然每个模块都应该有自己自己的名字。我们需要把这些名字拿到__init__.py里面, 才能使用。python3中即便没有这个__init__.py文件也不会报错,pyhon2二中就会报错。所以在python2中必须要有__init__.py这个文件。
"""

# 包的本质就是一种模块: 
"""
python包的目的不是为了运行的。而是被导入使用的, 被导入和被右键运行是截然不同的两件事,包是模块的一种形式,换句话说包的本质就是一种模块。
"""

二. 包的使用

1.导入包与_init_.py

# 包属于模块的一种,因而包以及包内的模块均是用来被导入使用的,而绝非被直接执行,首次导入包同样会做三件事:
"""
1. 执行包下的__init__.py文件
2. 产生一个新的名称空间用于存放__init__.py执行过程中产生的名字
3. 在当前执行文件所在的名称空间中得到一个以被导入包名为命名的名字, 名字指向__init__.py的名称空间.
"""

# 导包需要注意的3点问题: 
"""
# 1. 凡是在导入时带点的,点的左边都必须是一个包:
	关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如import 顶级包.子包.子模块,但都必须遵循这个原则。但对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。
# 2. 同名模块不冲突	
	包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间
# 3. 导入包本质就是在导入__init__.py文件
	import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件
"""

2.绝对导入与相对导入

  • 注意: 这里的导入指的是包内模块之间的互相导入, 且都是被导入的, 并不是被执行的.
"""
top                # 顶级包
├── __init__.py     
├── sub          # 子包
│   ├── __init__.py
│   ├── bbb.py
│   └── ccc.py
└── aaa.py      # 子模块
"""

# 一. 绝对导入:以顶级包为起始
"""
绝对导入是没有任何限制的,所以绝对导入是一种通用的导入方式
"""
# 1. 需求1: 让用户可以通过import top访问到aaa.py中的get功能
"""
from top.aaa import get  # 在top的__init__.py中写入(设计者)

import top # 用户执行文件(不改变用户调用方式)
top.get()
"""
# 2. 需求2: 包内部aaa.py需要用到ccc.py中的set函数功能
from top.sub.ccc import set  # 在aaa.py中写入(设计者)
"""
import top # 用户执行文件(不改变用户调用方式)
top.get()
"""

# 3. 需求3: 让用户可以通过import top访问到ccc.py中的set功能
"""
# 方式一: 不在sub的__init__.py中添加(设计者)
from top.sub.ccc import set # 在top下的__init__.py写入
# 方式二: 在sub的__init__.py中添加(设计者)
from top.sub import set  # 在top下的__init__.py写入
from top.sub.ccc import set # 在sub下的__init__.py写入

import top # 用户执行文件(不改变用户调用方式)
top.set()
"""

# 二. 相对导入:.代表当前文件所在的目录,..代表当前目录的上一级目录,依此类推
"""
# 强调1:..有非常大的局限性,就是这个点不能超出顶级包之外, 不能跳出顶头的包, 不然就会抛出异常: ValueError: attempted relative import beyond top-level package)
# 强调2: 相对导入不能跨出包。相对导入仅限于包内模块彼此之间
"""
# 1. 需求1: 让用户可以通过import top访问到aaa.py中的get功能
"""
from .aaa import get  # 在top下的__init__.py写入

import top # 用户执行文件(不改变用户调用方式)
top.get()
"""

# 2. 需求2: 包内部aaa.py需要用到ccc.py中的set函数功能
"""
from .sub.ccc import set  # 在aaa.py写入(设计者)

import top # 用户执行文件(不改变用户调用方式)
top.get()
"""

# 3. 需求3: 让用户可以通过import top访问到ccc.py中的set功能
"""
from .sub.ccc import set  # 在top下的__init__.py中写入

import top # 用户执行文件(不改变用户调用方式)
top.set()
"""


# 三. 补充: import也能使用绝对导入,导入过程中同样会依次执行包下的__init__.py,只是基于import导入的结果,使用时必须加上该前缀(不推荐)
# 需求: 让用户访问到ccc.py中的set功能
import top.sub.ccc.set??
set()

# 四. 提示: 相对导入只能用from  import 的形式,import ..aaa..ccc语法是不对的.

# 五. 推荐使用: 针对包内部模块之间的相互导入推荐使用相对导入(注意: 这里指的是内部模块之间)

# 六. 总结
"""
1、相对导入只能在包内部使用,用相对导入不同目录下的模块是非法的
2、无论是import还是from import,但凡是在导入时带点的,点的左边必须是包,否则语法错误
"""

3.from 包 import *

# 在使用包时同样支持from 包 import * ,毫无疑问*代表的是被导入的所有的名字,通用是用变量__all__来控制*代表的意思

__all__ = ['aaa', 'aaa1']  # 只能访问到aaa.py中的aaa, aaa1这两个名字

# 注意: 包内部的目录结构是包的开发者为了方便自己管理和维护代码而创建的, 这种目录结构对包的使用者往往是无用的. 设计者的目的就是通过操作__init__.py"隐藏"包内部的目录结构,降低用户导入的使用难度
# 用户可执行文件
import top
top.get()
top.set()

# top下的__init__.py中设置内容(提示: set在sub的bbb.py中, get在top下的aaa.py中)
from .aaa import get
from .sub.bbb import set
posted @ 2020-03-29 01:46  给你加马桶唱疏通  阅读(105)  评论(0编辑  收藏  举报