作者: 青蛙兄 分类: 进阶 发布时间: 2019-11-18 23:29

特殊的模块

Python支持目录吗?

实验:

项目中新建一个目录,使用下面的代码

import m  
print(m)  
print(type(m))  
print(dir(m)) #没有__file__ 

竟然可以导入目录m,m也是文件,就可以导入,不过问题是,目录怎么写代码?
pycharm中,创建Directory和创建Python Package不同,前者是创建普通的目录,后者是创建一个带有__init__.py文件的目录即包
python中,目录可以作为模块,这就是包,不过代码需要写在该目录下__init__.py 中

模块和包的总结

包能够更好的组织模块,尤其是大规模代码很多,可以拆分成很多子模块,便于使用某些功能就加载相应的子模块
包目录中__init__.py 是在包第一次导入的时候就会执行,内容可以为空,也可以用于该包初始化工作的代码,最好不要删除它(低版本不可删除)
导入子模块一定会加载父模块,但是导入父模块一定不会导入子模块
包目录之间只能使用.点号作为间隔符,表示模块及其子模块的层级关系

模块也是封装,如同类、函数、不过它能够封装变量、类、函数、不过它能够封装变量、类、函数
模块就是命名空间,其内部的顶层标识符,都是它的属性,可以通过__dict__或dir(module)查看
包也是模块,但模块不一定是包,包是特殊的模块,是一种组织方式,包含__path__属性

from json import encoder 之后,json.dump函数用不了,为什么? (不能用)
impor json.encoder之后呢?json.dump函数能用吗? (能用)

from json import encoder  
print(dir())  
#['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'encoder']  
import json.encoder  
print(dir())  
#['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'encoder', 'json']  

原因是from json import encoder之后,当前名词空间没有json,但是json模块已经加载过了,没有json的引用,无法使用dump函数
import json.encoder也加载json模块,但是当前名词空间有json,因此可以调用

绝对导入和相对导入

绝对导入

在import语句或者from导入模块,模块名词最前面不是以.点开头的
绝对导入总是去搜索模块搜索路径中找

相对导入

只能在包内使用,且只能只能用在from语句中
使用.点号,表示当前目录内
..表示上一级目录
不要在顶层模块中使用相对导入

举例a.b.c模块,c是模块,c的代码中,使用如下

from . import d #import a.b.decode

from ..import e #import a.e

from .d import x #a.b.d.x

from ..e import x # a.e.x

… 三点表示上上级

访问控制

下划线开头的模块名

或者_开头的模块是否能够被导入呢?

创建文件名为_xyz.py或者_xyz.py测试

都可以成功的导入,因为它们都是合法的标识符,就可以用作模块名

使用__all__

__all__是一个列表,元素是字符串,每一个元素都是一个模块内的变量名

__all__ = [‘_变量名’,’__变量名1′,’__变量名2__’]

 

总结:

一、使用from xyz import * 导入

1、如果模块没有__all__,from xyz import * 只导入非下划线开头的模块的变量,如果是包,子模块也不会导入,除非在__all__种设置,或__init__.py中使用相对导入

2、如果模块有__all__,from xyz import * 只导入__all__列表中指定的名称,哪怕这个名词是下划线开头的,或者是子模块

3、from xyz import * 方式导入,使用简单,但是其副作用是导入大量不需要使用的变量,甚至有可能造成名称的冲突,而__all__可以控制被导入模块在这种导入方式下能够提供的变量名称,就是为了阻止from xyz import * 导入过多的模块变量,从而避免冲突,因此,编写模块时,应该尽量加入__all__

 

二、from module import name1,name2 导入

这种方式的导入是明确的,哪怕是导入子模块,或者导入下划线开头的名称

程序员可以有控制的导入名称和其相应的对象

发表评论

电子邮件地址不会被公开。