4.包和模块
4.1包和模块的含义
在Python中,项目的组织结构从高到低依次是:包->模块->类->函数/变量。类和函数在后面的章节中讲解,本章主要讲包和模块。
Python包:Python项目下,包含__init__.py文件的文件夹,简称”Package”。
模块:Python项目下,包含Python代码的.py文件,简称”Module”。
Python包可以理解为文件夹,但Python包和文件夹之间还是有差别的。当一个文件夹包含了__init__.py文件,此时这个文件夹可以称为Python包。__init__.py的作用之一就是为了区分Python包和文件夹,即使__init__.py中什么也不写。
模块可以理解为后缀名是py的文件。
|--Python_Demo
|--pack1
p1_mod1.py
|--pack2
p2_mod1.py
mod1.py
main.py
pack1和pack2并不是Python包,因为内部没有包含__init__.py文件。
|--Python_Demo
|--pack1
p1_mod1.py
__init__.py
|--pack2
p2_mod1.py
__init__.py
mod1.py
main.py
pack1和pack2是Python包,因为其内部包含__init__.py文件;目录中以py为后缀名的都是模块。
4.2模块的导入
4.2.1 import语句
使用import语句来导入模块,使用运算符(.)来访问模块中的函数、变量等。
目录结构:
|--Python_Demo
|--pack1
p1_mod1.py
__init__.py
|--pack2
p2_mod1.py
__init__.py
mod1.py
main.py
# this is main.py
import mod1
print('main.py')
print('a = %d'%mod1.a,'b = %d'%mod1.b,'c = %d'%mod1.c)
# this is mod1.py
print('mod1.py')
a = 1
b = 2
c = 3
执行main.py的运行结果:
mod1.py
main.py
a = 1 b = 2 c = 3
模块的导入可以理解为py文件的拼接,在main.py文件中导入了mod1.py模块,相当于main.py文件上拼接了mod1.py。当开始执行时,会先执行mod1.py,再去执行main.py。
当模块导入后,可以使用运算符(.)来访问模块中的函数、变量。上述代码中,在main.py访问mod1.py中的a/b/c,需要加上模块名。
# this is main.py
import pack1.p1_mod1
print('main.py')
print('a = %d'%pack1.p1_mod1.a,'b = %d'%pack1.p1_mod1.b,'c = %d'%pack1.p1_mod1.c)
# this is p1_mod1.py
print('p1_mod1.py')
a = 1
b = 2
c = 3
执行main.py的运行结果:
p1_mod1.py
main.py
a = 1 b = 2 c = 3
当导入包(Package)内部的模块,import时需要加上package.module(模块的绝对路径);使用模块函数、变量时也需要加上package.module。
那么执行文件、模块、包和目录之间到底有什么关系呢?
目录结构:
|--Python_Demo
|--pack1
p1_mod1.py
__init__.py
|--pack2
p2_mod1.py
__init__.py
mod1.py
main.py
test.py
在上述目录中,main.py会被执行。其中,main.py被称为“入口文件”或“主模块”,main.py所在的目录称为“顶层目录”。
Python_Demo、test.py的目录等级相同;pack1、pack2、mod1.py、main.py的目录等级相同;p1_mod1.py、__init__.py的目录等级相同;p2_mod1.py、__init__.py的目录等级相同。
当以main.py为入口文件时,其上级目录中的模块无法被识别和导入,如test.py;其同级或下级目录中的模块可以被任意导入,即使下级目录的模块也可以导入同级目录的模块,举例:main.py->p1_mod1.py->p2_mod1.py->mod1.py。
# this is main.py
import pack1.p1_mod1
print('main.py')
print('p1m1 = %d'%pack1.p1_mod1.p1m1)
# this is pack1->p1_mod1.py
import pack2.p2_mod1
print('pack1->p1_mod1.py')
print('p2m1 = %d'%pack2.p2_mod1.p2m1)
p1m1 = 11
# this is pack2->p2_mod1.py
import mod1
print('pack2->p2_mod1.py')
print('m1 = %d'%mod1.m1)
p2m1 = 21
# this is mod1.py
print('mod1.py')
m1 = 1
main.py的执行结果:
mod1.py
pack2->p2_mod1.py
m1 = 1
pack1->p1_mod1.py
p2m1 = 21
main.py
p1m1 = 11
4.2.2 import...as...语句
当导入模块后,调用模块内的函数、变量都需要加package.module(模块的绝对路径)。若package.module名称过长,导致每次调用都很不方便,因此可以使用import...as...语句。
目录结构:
|--Python_Demo
|--pack1
p1_mod1.py
__init__.py
|--pack2
p2_mod1.py
__init__.py
mod1.py
main.py
# this is main.py
import pack1.p1_mod1 as pm
print('main.py')
print('a = %d'%pm.a,'b = %d'%pm.b,'c = %d'%pm.c)
# this is p1_mod1.py
print('p1_mod1.py')
a = 1
b = 2
c = 3
执行main.py的运行结果:
p1_mod1.py
main.py
a = 1 b = 2 c = 3
4.2.3 from...import...语句
当我们不想把整个模块都导入时,可以使用from...import...选择性导入变量、函数。
目录结构:
|--Python_Demo
|--pack1
p1_mod1.py
__init__.py
|--pack2
p2_mod1.py
__init__.py
mod1.py
main.py
# this is main.py
from pack1.p1_mod1 import a,b,c
print('main.py')
print('a = %d'%a,'b = %d'%b,'c = %d'%c)
# this is p1_mod1.py
print('p1_mod1.py')
a = 1
b = 2
c = 3
执行main.py的运行结果:
p1_mod1.py
main.py
a = 1 b = 2 c = 3
使用from...import...导入模块函数、变量,其使用不需要再加package.module(模块的绝对路径),可以直接使用。优点:使用函数、变量比较方便。
若函数、变量前没有package.module,若导入模块和入口文件发生名称冲突该怎么办?
目录结构:
|--Python_Demo
|--pack1
p1_mod1.py
__init__.py
|--pack2
p2_mod1.py
__init__.py
mod1.py
main.py
# this is main.py
from pack1.p1_mod1 import a,b,c
print('main.py')
print('a = %d'%a,'b = %d'%b,'c = %d'%c)
a = 4
b = 5
c = 6
print('a = %d'%a,'b = %d'%b,'c = %d'%c)
# this is p1_mod1.py
print('p1_mod1.py')
a = 1
b = 2
c = 3
执行main.py的运行结果:
p1_mod1.py
main.py
a = 1 b = 2 c = 3
a = 4 b = 5 c = 6
名称冲突:main.py中的变量a/b/c对pack1.p1_mod1的变量a/b/c重新赋值,即覆盖。因为pack1.p1_mod1先执行,main.py后执行。
4.2.4 from...import *语句
使用from...import *和import ...的作用是相同的,一个是从变量、函数层数全部导入,一个是导入整个模块。
但from...import *可以和__all__一起使用。在__all__中可以指定哪些变量、函数可以被from...import *导出。
目录结构:
|--Python_Demo
|--pack1
p1_mod1.py
__init__.py
|--pack2
p2_mod1.py
__init__.py
mod1.py
main.py
# this is main.py
from pack1.p1_mod1 import *
print('main.py')
print('a = %d'%a,'b = %d'%b)
# this is p1_mod1.py
__all__ = ['a','b']
print('p1_mod1.py')
a = 1
b = 2
c = 3
执行main.py的运行结果:
p1_mod1.py
main.py
a = 1 b = 2
4.3 __pycache__的隐藏和__init__.py的使用
4.3.1隐藏__pycache__
当在Python代码中导入模块时,会产生*.pyc文件。*.pyc文件的作用是提高模块的加载速度,但不会提高代码的执行速度。
为了避免__pycache__对Python项目文件的影响,可以将其隐藏。
选择“文件”->“首选项”->“设置”,输入”exclude”,在用户设置的Files:Exclude中添加模式**/__pycache__即可。
4.3.2 __init__.py的用法
当导入包内部的模块时,它会最先导入__init__.py。
目录结构:
|--Python_Demo
|--pack1
p1_mod1.py
__init__.py
|--pack2
p2_mod1.py
__init__.py
mod1.py
main.py
# this is main.py
import pack1.p1_mod1 as pm
print('main.py')
print('a = %d'%pm.a,'b = %d'%pm.b,'c = %d'%pm.c)
# this is __init__.py
print('__init__.py')
# this is p1_mod1.py
print('p1_mod1.py')
a = 1
b = 2
c = 3
执行main.py的运行结果:
__init__.py
p1_mod1.py
main.py
a = 1 b = 2 c = 3
可以看到在导入p1_mod1.py之前,导入了__init__.py模块。
__init__.py用法1:__all__配合from package import *使用。
|--Python_Demo
|--pack1
p1_mod1.py
__init__.py
|--pack2
p2_mod1.py
__init__.py
mod1.py
main.py
# this is main.py
from pack1 import *
print('main.py')
print('a = %d'%p1_mod1.a,'b = %d'%p1_mod1.b,'c = %d'%p1_mod1.c)
# this is __init__.py
print('__init__.py')
__all__ = ['p1_mod1']
# this is p1_mod1.py
print('p1_mod1.py')
a = 1
b = 2
c = 3
执行main.py的运行结果:
__init__.py
p1_mod1.py
main.py
a = 1 b = 2 c = 3
这里需要注意的是from package import *是导入包内部的全部模块,必须配合__all__使用,不然一个模块都无法导入。而from package.module import *是导入模块内的全部变量,可以使用或不使用__all__。
__init__.py用法2:使用import package来导入Python标准库。
目录结构:
|--Python_Demo
|--pack1
p1_mod1.py
__init__.py
|--pack2
p2_mod1.py
__init__.py
mod1.py
main.py
# this is main.py
import pack1
print('main.py')
print('math.pi = %f'%pack1.math.pi)
# this is __init__.py
import math
import sys
import os
print('__init__.py')
执行main.py的运行结果:
__init__.py
main.py
math.pi = 3.141593
使用import package只会导入包内部的__init__.py模块(其他模块无法导入),在__init__.py中可以设置需要导入的Python标准库。
注:当然也可以使用前面的from package import *方法,在__init__.py模块设置需要导入的Python标准库。
4.3.3模块导入总结
(1)同一模块,只会被导入一次。
(2)模块导入需要避免循环导入。
(3)使用import导入模块和导入包之间有很多差别。若是导入包,则只会导入包下的__init__.py模块。
(4)使用from...import *导入模块内的所有函数、变量和导入包下的所有模块有很大差别。若是导入包内部的所有模块,则必须在__init__.py模块中使用__all__。
4.4 dir()函数
4.4.1 dir()函数
dir()可以查看模块中中的定义(变量、函数、类),返回一个字符串列表。
# this is main.py
import sys
INFOS = dir(sys)
print(INFOS)
print(sys.argv)
在终端输入python .\main.py 123456,运行结果如下:
['__breakpointhook__', '__displayhook__', '__doc__', '__excepthook__', '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__', '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache', '_current_frames', '_debugmallocstats', '_enablelegacywindowsfsencoding', '_framework', '_getframe', '_git', '_home', '_xoptions', 'api_version', 'argv', 'base_exec_prefix', 'base_prefix', 'breakpointhook', 'builtin_module_names', 'byteorder', 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dllhandle', 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'float_repr_style', 'get_asyncgen_hooks', 'get_coroutine_origin_tracking_depth', 'get_coroutine_wrapper', 'getallocatedblocks', 'getcheckinterval', 'getdefaultencoding', 'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettrace', 'getwindowsversion', 'hash_info', 'hexversion', 'implementation', 'int_info', 'intern', 'is_finalizing', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'set_asyncgen_hooks', 'set_coroutine_origin_tracking_depth', 'set_coroutine_wrapper', 'setcheckinterval', 'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr', 'stdin', 'stdout', 'thread_info', 'version', 'version_info', 'warnoptions', 'winver']
['.\\main.py', '123456']
其中标准库sys中的argv参数是用来获取命令行参数。
当dir()函数内无任何参数时,会列出当前作用域中的定义。
# this is main.py
INFOS = dir()
print(INFOS)
运行结果:
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
__annotations__是内置函数,作用:函数注释。
__builtins__是对内置模块的引用。
在Python中有一个内置模块,其包含了很多Python常用的函数。因此在Python启动后且未执行任何代码之前,会加载该内置模块。在Python2.x中该内置模块命名被__builtin__;而在Python3.x中被重命名为builtins。
以Python3.x为例,当在主模块__main__中,__builtins__是对内置模块builtins的引用;在非__main__模块中,__builtins__是对__builtin__.__dict__的引用。
__cached__是内置变量,表示导入模块的缓存。
__doc__是内置变量,表示模块的注释。
__file__是内置变量,表示模块的路径。
__loader__是加载器在导入模块上设置的属性,访问它时将会返回加载器对象本身。
__name__是内置变量,表示模块的完整名称。若是入口文件,则表示主模块__main__。
__package__是内置变量,表示模块所属的包。
4.4.2常用的内置变量
在前面的dir()函数中,打印出内置变量__doc__、__file__、__name__、__package__。在这一节,通过代码来查看在主模块(入口文件)和普通模块中,这些内置变量的具体数值。
目录结构:
|--Python_Demo
|--pack1
p1_mod1.py
__init__.py
|--pack2
p2_mod1.py
__init__.py
mod1.py
run.py
'''this is run.py'''
import pack1.p1_mod1
print("__doc__ = %s"%__doc__)
print("__file__ = %s"%__file__)
print("__package__ = %s"%__package__)
print("__name__ = %s"%__name__)
'''this is p1_mod1.py'''
print("__doc__ = %s"%__doc__)
print("__file__ = %s"%__file__)
print("__package__ = %s"%__package__)
print("__name__ = %s"%__name__)
执行run.py的运行结果:
__doc__ = this is p1_mod1.py
__file__ = D:\Python\pack1\p1_mod1.py
__package__ = pack1
__name__ = pack1.p1_mod1
__doc__ = this is run.py
__file__ = .\run.py
__package__ = None
__name__ = __main__
可以看出在主模块(入口文件)中,其__name__是__main__。
4.4.3 __name__的用法
可以在py文件中使用if对__name__进行判断。若是__main__,则表示此模块是入口文件;否则表示这是一个普通模块。
'''this is run.py'''
if __name__ == "__main__":
print('这是入口文件')
else:
print('这是普通模块')
运行结果:
这是入口文件