模块和包
1.模块
随着程序的变大及代码的增多,为了更好地维护程序,一般会把代码进行分类,分别放在不同的文件中。公共类、函数都可以放在独立的文件中,这样其他多个程序都可以使用,而不必把这些公共性的类、函数等在每个程序中复制一份,这样独立的文件就叫作模块,它们的扩展名是.py。
1.1标准库中的模块
当我们安装好Python后,默认其实安装了非常多的模块,这些模块称为Python的标准库。简单来说,标准库就是那些默认安装上的模块。
模块默认安装在“C:\Users\用户001\AppData\Local\Programs\Python \Python36\Lib”文件夹下.
还可以在解释器中使用help(‘模块名’)方法查看json模块的各种说明
• NAME:模块的名字,可以由全局变量__name__得到。
• DESCRIPTION:模块的描述和使用的演示。
• FUNCTIONS:模块支持的方法。
• DATA:数据结构形式。
• VERSION:模块的版本号。
• AUTHOR:模块的作者。
• FILE:该模块在系统中的文件位置。
在help方法中指定具体的模块为需要查看的模块,如果不指定模块而是写modules,则是查看当前安装的所有模块,结果如图所示
2.导入模块
2.1简单的导入
默认的模块,要导入这些模块特别简单,只需要一行:
import 模块名
比如导入time模块,可以先用help看看它有什么方法
time模块有clock、gmtime等方法,我们可以根据说明了解每个方法的返回值或参数。
1.在IDEL中导入
2.在解释器中导入
from…import语句允许开发人员只导入模块的一部分,如导入某个具体的方法、某个变量。其语法形式为:
from 模块 import 方法(变量)名1, 方法(变量)名2…
当直接导入某个函数时,不需要再指定这个函数的模块名称,比如之前用time.gmtime(),而现在直接用gmtime()就可以了。
使用from…import语句的好处是,不需要把模块的所有内容都导入到当前的工作区域中,这极大地提高了空间的使用效率。
如果import后面加了*符号,则还是会导入全部模块。与import简单导入语句的区别是:这种导入方式不会导入以下画线(_)开头的名称。
3.包
包与文件夹对应。使用包的方式与使用模块的方式类似,唯一需要注意的是,当文件夹当作包使用时,文件夹需要包含__init__.py文件,主要是为了避免将文件夹名当作普通的字符串。__init__.py的内容可以为空,一般用来进行包的某些初始化工作或设置__all__值,__all__是在from包名称import *语句使用的,全部导出定义过的模块。
包中的模块有很多,可直接导入包,也可以导入包中的模块。
(1)导入包中的模块
import 包名称.模块名称
(2)使用from…import形式
from包名称import 模块名称
(3)使用from…import *形式
from 包名称import *
(4)导入包中模块的指定方法或变量
from 包名称.模块名称 import 方法名称
4.命名空间
命名空间是名称到对象的映射集合,这种说法比较抽象。举个例子来说,一个计算机由主板、CPU、硬盘、内存等各部分组成,而主板、CPU、硬盘等都是一个个与真实物品一一对应的名字,计算机则是由这么多叫着不同名字的东西组合起来的,那么计算机就算是一个命名空间,换句话说命名空间就是不同的变量和变量所指向的对象的集合。
命名空间是一个广义的概念,一个总的名字包含若干个对象,这就叫命名空间。比如模块是命名空间,一个模块包含了一些变量、函数和类;包也是命名空间,它包含了一些模块和子包;类也是命名空间,它包含自己的属性和方法。命名空间在Python中是一个底层而简单的概念,而类、模块、包都是通过命名空间实现的高层概念,就像整数、小数、字符串都是对二进制数进行包装而来的。
命名空间的作用是能够提供对变量名的层次访问。Python中有大量的对象,又有更多的变量指向这些对象,而命名空间能够把这些变量名包装起来提供层次性的访问。
图中的变量a、b、c、d等都是指向不同对象的变量名,如果没有命名空间,所有的变量名的层次均为一样,而一旦加了命名空间AA和BB,变量名如图8.9所示可以分成各个层次。例如,现在调用变量a,则要如下代码:
print(AA.a)
如果要调用变量b,因为它还在命名空间BB,所以层次就要更低一层,代码如下:
print(AA.BB.b)
从上面可以看出,命名空间的作用是有层次地管理变量和变量所指向对象,而这又是类、包、模块功能的基础。Python也正是使用命名空间实现了类、模块、包等更高级的功能。
1.全局命名空间
全局命名空间是一个特殊的命名空间,一旦进入Python的解释器,就创建了一个全局命名空间(global name space),这是全局唯一的命名空间。该命名空间已经有若干个成员变量在里面,可以用dir函数查看命名空间有几个变量名称,例如:
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__',
'__spec__', 'sys']
__builtins__是Python的内置模块,里面包括了各种内置的类型函数等,__doc__是该命名空间的注释文字,__name__是用来标识命名空间的。如果命名空间是全局命名空间,那么__name__就等于__main__,例如:
>>> print(__name__)
__main__
一个模块文件被import时,它的命名空间__name__名字就和模块文件的名字一样,例如:
>>> import sys
>>> sys.__name__
'sys'
全局命名空间的内容可以使用内置函数globals获得该命名空间的内容,例如:
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class
'_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__':
<module 'builtins' (built-in)>}
上面的例子是在Pyshell输入globals函数得到的结果,可以看出当前全局变量包括__builtins__内置模块和__name__、__doc__等属性变量。
2.局部命名空间
局部命名空间就是一个代码块所创造的一个临时的命名空间,当进入该代码块的时候,局部变量空间被创建,当退出这个代码块时,该局部变量空间就被销毁。例如定义一个函数TestA:
>>> def TestA():
a=3
print(locals())
print(globals())
当调用TestA的时候,就生成该函数的命名空间。当TestA返回或抛出异常的时候,局部命名空间就被删除,获得局部命名空间的内容可以用locals函数,TestA运行的结果如下:
>>> TestA()
{'a': 3}
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class
'_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__':
<module 'builtins' (built-in)>, 'sys': <module 'sys' (built-in)>, 'TestA': <function TestA at
0x000002715144A598>}
在Python查找一个变量名的时候,有一个LGB原则,L就是局部命名空间(local name space),G就是全局命名空间(global name space),B就是内置命名空间(built in space)。也就是说,当使用一个变量名的时候,程序优先使用局部命名空间里的,如果局部命名空间没有,再去查找全局命名空间,最后查找内置命名空间。例如下面的例子:
>>> a=0
>>> def TestA():
a=4
>>> TestA()
>>> print(a)
0
上面的例子中,全局命名空间下有一个变量a,而TestA下也有一个局部变量a,当将a和数字对象4绑定的时候,根据LGB原则,和4绑定的变量a是局部命名空间下的,与全局命名空间下的变量a没有关系,因此打印a得到的结果仍为0。
在局部命名空间里也可以通过global关键字指定变量为全局命名空间,将TestA的代码改造如下:
>>> def TestA():
global a
a=4
print(locals())
上面的TestA在a前面加了global关键字,这样a就不属于局部命名空间下的变量,而是全局命名空间下的变量,因此当对a做改变的时候,全局命名空间下的变量a也就改变了。