Python模块与包
初识模块什么是模块
为什么要有模块
怎么使用模块 如果是自定义模块需要先创建一个 #!/usr/bin/env python3 # -*- coding: utf-8 -*- 这是一个模块 print("模块foo --->") x = 1def get(): print(x) change(): global x x = 0 然后再到执行程序中去导入使用: 对于内置模块来说 import datetime (datetime.datetime.now()) 对于自定义模块来说 import foo 文件名为foo.py,模块名为foo (foo.x) ==== 执行结果 ==== """ 2020-05-21 22:29:28.448299 模块foo ---> 1 """ 模块与Py文件两种导入方式的首次导入发生的事儿(foo.x) 使用import首次导入模块会发生3件事: 1.执行foo.py 2.产生foo.py的命名空间,将foo.py运行过程中产生的名字都丢到foo的命名空间中 3.在当前run.py也就是程序文件中产生一个名字为foo.该名字指向foo名称空间如有重复导入,不必再次经历首次导入的三步骤。(命名空间以存在,常驻内存中..) """ ==== 执行结果 ====""" 模块foo ---> 1 """ from foo import x (x) 使用from ... import ... 首次导入模块会发生3件事: 1.执行foo.py 2.产生foo.py的命名空间,将foo.py运行过程中产生的名字都丢到foo的命名空间中 3.在当前run.py也就是程序文件中产生一个名字为x.该名字指向foo名称空间中的同名变量所指向的内存空间 如有重复导入,不必再次经历首次导入的三步骤。(命名空间以存在,常驻内存中..) 模块foo ---> 1 """ .Py文件的两种用途 一个Python文件有两种用途,一种被当主程序/脚本执行,另一种被当模块导入,为了区别同一个文件的不同用途,每个py文件都内置了 作为模块 foo.py ... if __name__ == '__main__': foo.py被当做脚本执行时运行的代码 else: foo.py被当做模块导入时运行的代码 通常我们会在if的子代码块中编写针对模块功能的测试代码,这样 -*- coding: utf-8 -*- ) x = 1 x x = 0 ': Ps:由于导入模块时会先执行一遍模块文件。故可以采用此种方式做功能测试 get() : 不运行get..) 执行结果如下: 1.当将foo.py当做主程序运行时,会 print("模块foo --->") 后 执行get()方法。 2.当将foo.py当做模块进行导入时,会 print("模块foo --->") 后 print("不运行get..") 。 """ 模块导入相关import导入模块
def get(): run.py全局命名空间下定义了get() run.py ... get()) foo.get() 运行依旧是foo中的get() x = 33333 print(foo.x) 拿foo中的x,就算foo中没有定义x也不会来run.py中找x foo.change() 修改的是foo中的x内存指向,与run.py中的x无关。即使foo中没有x也不会修改run.py中的x (foo.x) (x) 强调1:模块名.名字,是指名道姓的问某一个模块要名字对应的值,不会与当前命名空间发生冲突。(即使模块中没有该名字,也不会来执行文件中找) 强调2:无论是查看还是修改操作的都是模块本身,与调用位置(执行文件)无关。 模块foo ---> 1 1 0 33333 """ from .. import .. 导入模块
print(x) 此刻的x指向的内存地址是foo.x指向的内存地址 x = 33333 此刻的x已经改变指向 强调1:使用from .. import .. 的方式可能会导致命名空间冲突的问题。 模块foo ---> 1 33333 """ 导入模块的规范导入模块的规范: 1.Python内置模块 2.第三方模块 3.程序员自定义模块 模块是第一类对象(允许被当做参数传入等等...) 自定义的模块命名应该采用纯小写+下划线的风格 Ps: 尽管Python2中有些模块是以驼峰体进行命名,但是在Python3中他们都全部变为纯小写了。 如:Python2中的PyMySql已经命名为pymysql import datetime,time,os 使用 , 逗号 可以一行导入多个模块.但是不建议这么做。 import collections as coll 使用 as 可以为模块取一个别名。 import x,get,change 使用 , 逗号 可以一行导入同个模块下的多个功能.但是不建议这么做。 import * 导入模块中的所有功能。(大多数情况下不推荐使用,视情况而定) 模块查找相关模块查找优先级
sys.modules查看内存模块
sys 执行foo,开始首次导入三步骤 del foo <=== 此时已经将foo模块加载至内存中,即使删除绑定关系也无妨 foo" in sys.modules) <--- 第二次导入不会执行首次导入三步骤。 (sys.modules) 查看已经加载至内存中的模块 ==== 执行结果 ==== Ps: <--- 可以看到foo即使被del也依旧存在于内存中 模块foo ---> True {'sys': <module 'sys' (built-in)>,'builtins': <module 'builtins' (built-in)>,'_frozen_importlib': <module '_frozen_importlib' (frozen)>,'_imp': <module '_imp' (built-in)>,'_warnings': <module '_warnings' (built-in)>,'_frozen_importlib_external': <module '_frozen_importlib_external' (frozen)>,'_io': <module 'io' (built-in)>,'marshal': <module 'marshal' (built-in)>,'nt': <module 'nt' (built-in)>,'_thread': <module '_thread' (built-in)>,'_weakref': <module '_weakref' (built-in)>,'winreg': <module 'winreg' (built-in)>,'time': <module 'time' (built-in)>,'zipimport': <module 'zipimport' (frozen)>,'_codecs': <module '_codecs' (built-in)>,'codecs': <module 'codecs' from 'C:Python38libcodecs.py'>,'encodings.aliases': <module 'encodings.aliases' from 'C:Python38libencodingsaliases.py'>,'encodings': <module 'encodings' from 'C:Python38libencodings__init__.py'>,'encodings.utf_8': <module 'encodings.utf_8' from 'C:Python38libencodingsutf_8.py'>,'_signal': <module '_signal' (built-in)>,'__main__': <module '__main__' from 'C:/Users/Administrator/PycharmProjects/learn/ModelsLearn/run.py'>,'encodings.latin_1': <module 'encodings.latin_1' from 'C:Python38libencodingslatin_1.py'>,'_abc': <module '_abc' (built-in)>,'abc': <module 'abc' from 'C:Python38libabc.py'>,'io': <module 'io' from 'C:Python38libio.py'>,'_stat': <module '_stat' (built-in)>,'stat': <module 'stat' from 'C:Python38libstat.py'>,'_collections_abc': <module '_collections_abc' from 'C:Python38lib_collections_abc.py'>,'genericpath': <module 'genericpath' from 'C:Python38libgenericpath.py'>,'ntpath': <module 'ntpath' from 'C:Python38libntpath.py'>,'os.path': <module 'ntpath' from 'C:Python38libntpath.py'>,'os': <module 'os' from 'C:Python38libos.py'>,'_sitebuiltins': <module '_sitebuiltins' from 'C:Python38lib_sitebuiltins.py'>,'sitecustomize': <module 'sitecustomize' from 'D:ApplicationPyCharm 2020.1pluginspythonhelperspycharm_matplotlib_backendsitecustomize.py'>,'site': <module 'site' from 'C:Python38libsite.py'>,'foo': <module 'foo' from 'C:UsersAdministratorPycharmProjectslearnModelsLearnfoo.py'>} """ sys.path的应用
(sys.path) 当内存中没有模块路径时,将按照sys.path的路径顺序依次在硬盘中查找。 Ps:Pycharm执行该脚本时产生的结果 模块foo ---> [ 'C:UsersAdministratorPycharmProjectslearnModelsLearn','C:UsersAdministratorPycharmProjectslearn',# 不存在 'D:ApplicationPyCharm 2020.1pluginspythonhelperspycharm_display',# 不存在 'C:Python38python38.zip','C:Python38DLLs','C:Python38lib','C:Python38','C:Python38libsite-packages','D:ApplicationPyCharm 2020.1pluginspythonhelperspycharm_matplotlib_backend' # 不存在 ] Ps:Python解释器执行该脚本时产生的结果 模块foo ---> [ 'C:UsersAdministratorPycharmProjectslearnModelsLearn','C:Python38python38.zip','C:Python38libsite-packages'] """ 包包与__init__
包可以当做一系列模块的集合体(包本身也是一个模块) 自定义包: my_plugin/ #顶级包 ├── __init__.py ├── tools #子包 │ ├── __init__.py │ ├── f1.py │ └── f2.py └── m1.py #子模块 foo.py run.py """ === my_plugin/__init__.py === from . m1 tools === my_plugin/ m1.py === plugin_m1(): plugin_m1...) === my_plugin/tools/__init__.py === f1 f2 === my_plugin/tools/f1.py === tools_f1(): tools_f1...) === my_plugin/tools/f2.py === tools_f2(): tools_f2...") 使用者 - 包导入强调三点
根据包名使用各个功能 from ModelsLearn my_plugin my_plugin.m1.plugin_m1() my_plugin.tools.f1.tools_f1() my_plugin.tools.f2.tools_f2() 引入某一个单独的文件 from ModelsLearn.my_plugin m1 m1.plugin_m1() 引入单独的某一个功能 from ModelsLearn.my_plugin.m1 plugin_m1 plugin_m1() plugin_m1... tools_f1... tools_f2... plugin_m1... plugin_m1... """ 开发者 - 包内绝对导入
my_plugin/__init__.py# from . import m1 # 对于开发者来说,只要该文件不是执行文件就可以使用 from . import xxx from . import tools === Ps === : 为了使用者的使用方便。我们可以更加详细的导入(此处导入为绝对导入) from my_plugin.m1 plugin_m1 from my_plugin.tools.f1 tools_f1 from my_plugin.tools.f2 tools_f2 run.py 执行文件 使用者可以更简单的使用了 my_plugin my_plugin.plugin_m1() my_plugin.tools_f1() my_plugin.tools_f2() 开发者 - 包内相对导入
my_plugin/__init__.py from . import m1 # 对于开发者来说,只要该文件不是执行文件就可以使用 from . import xxx === Ps === : 使用 from . import xxx 的文件不可被当做执行文件执行。只能被当做模块 from .m1 from .tools.f1 tools_f1 from .tools.f2 import tools_f2 扩展:循环导入问题及解决方式
=== run.py === 结构如下: - foo1.py - foo2.py - run.py import foo1 首次导入,执行foo1.py (foo1.x) === foo1.py === from foo2 import y 首次导入,执行foo2.py x = 10 根本来不及将x放入foo1的模块命名空间中,就又去执行foo2去了 === foo2.py === from foo1 foo1 二次导入,不会执行。尝试拿到x,抛出异常。 y = 20 由于第一行是导入x。 但是foo1中并没有把x放入foo1模块命名空间中去, 直接抛出异常导致foo2的y也放不进foo2的模块命名空间中去 执行run.py :Python38python3.exe C:/Users/Administrator/PycharmProjects/learn/ModelsLearn/run.py Traceback (most recent call last): File C:/Users/Administrator/PycharmProjects/learn/ModelsLearn/run.py",line 4,in <module> foo1 File C:UsersAdministratorPycharmProjectslearnModelsLearnfoo1.py y File C:UsersAdministratorPycharmProjectslearnModelsLearnfoo2.py x ImportError: cannot import name x' from partially initialized module foo1' (most likely due to a circular ) (C:UsersAdministratorPycharmProjectslearnModelsLearnfoo1.py) 可以看到。是 x 抛出的异常,原因上面说的很清楚了,x并没有放入foo1的模块命名空间中去,但是foo2的x尝试将内存指向foo1中的x的内存指向 解决方案1 === run.py === foo1 x = 10 先将 x 放入 foo1 的模块命名空间中,就没问题了。 y = 20 x 解决方案2 init(): y x = 10 init() 函数定义阶段不会执行,最后调用时x也是已经放在了 foo1 的模块命名空间中。也不会抛出异常 x y = 20 init() 扩展:编写规范模块!/usr/bin/env python #通常只在类unix环境有效,作用是可以使用脚本名来执行,而无需直接调用解释器。 The module is used to...模块的文档描述 import sys 导入模块 x=1 定义全局变量,如果非必须,则最好使用局部变量,这样可以提高代码的易维护性,并且可以节省内存提高性能 class Foo: 定义类,并写好类的注释 Class Foo is used to...' passdef test(): 定义函数,并写好函数的注释 Function test is used to…主程序 test() 在被当做脚本执行时,执行此处的代码 扩展:* 与 __all__foo.py __all__ = [y"] #该列表中所有的元素必须是字符串类型,每个元素对应foo.py中的一个名字 x = 10 y = 20 z = 30 也就是说,当使用 from ModelsLearn.foo import * 的时候,* 只能拿到 __all__ 中存在的名字。 run.py from ModelsLearn.foo import * 正常访问 print(y) print(z) 抛出异常 10 20 Traceback (most recent call last): File "C:/Users/Administrator/PycharmProjects/learn/ModelsLearn/run.py",line 9,in <module> print(z) # 抛出异常 NameError: name 'z' is not defined """ ? (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |