Python模块与包

Python模块与包,第1张

概述初识模块 什么是模块 模块就是一系列功能的集合体,分为三大类: 1、内置的模块 2、第三方模块 3、自定义的模块 一个Python文件本身就是一个模块。例如:文件名为m.py,其模块名则为m。 Ps: 初识模块什么是模块
@H_404_9@  模块就是一系列功能的集合体,分为三大类:

@H_404_9@     1、内置的模块

@H_404_9@     2、第三方模块

@H_404_9@     3、自定义的模块

  一个Python文件本身就是一个模块。例如:文件名为m.py,其模块名则为m

@H_404_9@  Ps:模块分为四种类型:

@H_404_9@     1、使用Python编写的.py文件

@H_404_9@     2、已被编译为共享库或DLL的C或C扩展

@H_404_9@     3、把一系列模块组织到一起的文件夹。(注:文件夹下有个__init__.py文件)

为什么要有模块
@H_404_9@  1.内置与第三方模块可以拿来就用,无需定义,这种拿来主义可以极大的提升自己的开发效率。

@H_404_9@  2.自定义的模块可以将程序各部分常用的功能提取出来放到一个模块中为大家共享使用,好处是减少了代码冗余,程序组织结构更加清晰。

怎么使用模块@H_404_9@  如果是自定义模块需要先创建一个.py文件:

@H_404_9@

#!/usr/bin/env python3# -*- Coding: utf-8 -*- 这是一个模块print("模块foo --->")x = 1def get():    print(x) change():    global x    x = 0
@H_404_9@  然后再到执行程序中去导入使用:

 对于内置模块来说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"""
@H_404_9@

from foo import x (x)使用from ... import ... 首次导入模块会发生3件事:    1.执行foo.py    2.产生foo.py的命名空间,将foo.py运行过程中产生的名字都丢到foo的命名空间中    3.在当前run.py也就是程序文件中产生一个名字为x.该名字指向foo名称空间中的同名变量所指向的内存空间如有重复导入,不必再次经历首次导入的三步骤。(命名空间以存在,常驻内存中..)模块foo --->1"""
@H_404_9@

.Py文件的两种用途@H_404_9@  一个Python文件有两种用途,一种被当主程序/脚本执行,另一种被当模块导入,为了区别同一个文件的不同用途,每个py文件都内置了__name__变量,该变量在py文件被当做脚本执行时赋值为__main__,在py文件被当做模块导入时赋值为模块名。

@H_404_9@  作为模块foo.py的开发者,可以在文件末尾基于__name__在不同应用场景下值的不同来控制文件执行不同的逻辑

 foo.py...if __name__ == '__main__':    foo.py被当做脚本执行时运行的代码else:    foo.py被当做模块导入时运行的代码
@H_404_9@  通常我们会在if的子代码块中编写针对模块功能的测试代码,这样foo.py在被当做脚本运行时,就会执行测试代码,而被当做模块导入时则不用执行测试代码。

 -*- 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导入模块
@H_404_9@  强调1:模块名.名字,是指名道姓的问某一个模块要名字对应的值,不会与当前命名空间发生冲突。(即使模块中没有该名字,也不会来执行文件中找)

@H_404_9@  强调2:无论是查看还是修改 *** 作的都是模块本身,与调用位置(执行文件)无关。

@H_404_9@  使用import导入模块的优缺点:

@H_404_9@    优点:肯定不会与当前名称空间中的名字冲突

@H_404_9@    缺点:使用模块中功能或变量时需加前缀

def get():  run.py全局命名空间下定义了get()    run.py ... get())foo.get()  运行依旧是foo中的get()x = 33333print(foo.x)  拿foo中的x,就算foo中没有定义x也不会来run.py中找xfoo.change()  修改的是foo中的x内存指向,与run.py中的x无关。即使foo中没有x也不会修改run.py中的x(foo.x)(x)强调1:模块名.名字,是指名道姓的问某一个模块要名字对应的值,不会与当前命名空间发生冲突。(即使模块中没有该名字,也不会来执行文件中找)强调2:无论是查看还是修改 *** 作的都是模块本身,与调用位置(执行文件)无关。模块foo --->11033333"""
from .. import .. 导入模块
@H_404_9@  强调1:使用from .. import .. 的方式可能会导致命名空间冲突的问题。

@H_404_9@  使用from .. import ..导入模块的优缺点:

@H_404_9@    优点:在使用模块中功能时,代码更加精简

@H_404_9@    缺点:容易与当前命名空间发生混淆。

print(x)  此刻的x指向的内存地址是foo.x指向的内存地址x = 33333 此刻的x已经改变指向强调1:使用from .. import .. 的方式可能会导致命名空间冲突的问题。模块foo --->133333"""
导入模块的规范
导入模块的规范:    1.Python内置模块    2.第三方模块    3.程序员自定义模块模块是第一类对象(允许被当做参数传入等等...)自定义的模块命名应该采用纯小写+下划线的风格    Ps:        尽管Python2中有些模块是以驼峰体进行命名,但是在python3中他们都全部变为纯小写了。        如:Python2中的PyMysqL已经命名为pyMysqLimport datetime,time,os  使用 , 逗号 可以一行导入多个模块.但是不建议这么做。import collections as coll  使用 as 可以为模块取一个别名。import x,get,change  使用 , 逗号 可以一行导入同个模块下的多个功能.但是不建议这么做。import *    导入模块中的所有功能。(大多数情况下不推荐使用,视情况而定)
模块查找相关模块查找优先级
@H_404_9@  无论是import还是from .. import .. 在导入模块时都涉及到查找的问题。

@H_404_9@  优先级:

@H_404_9@     1.内存(内置模块)

@H_404_9@     2.硬盘(sys.path

@H_404_9@当一个模块被导入过一次后,就会加载至内存中,重复导入便可直接从内存中拿到该模块。

sys.modules查看内存模块
@H_404_9@  1.sys.modules是导入模块后最先查找的路径顺序,当模块名不存在于该字典时将去硬盘中进行查找。

@H_404_9@  2.当首次导入一个模块之后,该模块会在此次执行文件运行的过程中将首次导入的模块路径存放至内存中,del该模块后解除变量名与其绑定关系。(只要程序再运行,二次导入都从内存中导入)

@H_404_9@  3.当二次导入该模块时依照查找顺序直接从内存就可导入该模块。

 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:\python38\lib\codecs.py'>,'enCodings.aliases': <module 'enCodings.aliases' from 'C:\python38\lib\enCodings\aliases.py'>,'enCodings': <module 'enCodings' from 'C:\python38\lib\enCodings\__init__.py'>,'enCodings.utf_8': <module 'enCodings.utf_8' from 'C:\python38\lib\enCodings\utf_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:\python38\lib\enCodings\latin_1.py'>,'_abc': <module '_abc' (built-in)>,'abc': <module 'abc' from 'C:\python38\lib\abc.py'>,'io': <module 'io' from 'C:\python38\lib\io.py'>,'_stat': <module '_stat' (built-in)>,'stat': <module 'stat' from 'C:\python38\lib\stat.py'>,'_collections_abc': <module '_collections_abc' from 'C:\python38\lib\_collections_abc.py'>,'genericpath': <module 'genericpath' from 'C:\python38\lib\genericpath.py'>,'ntpath': <module 'ntpath' from 'C:\python38\lib\ntpath.py'>,'os.path': <module 'ntpath' from 'C:\python38\lib\ntpath.py'>,'os': <module 'os' from 'C:\python38\lib\os.py'>,'_sitebuiltins': <module '_sitebuiltins' from 'C:\python38\lib\_sitebuiltins.py'>,'sitecustomize': <module 'sitecustomize' from 'D:\Application\PyCharm 2020.1\plugins\python\helpers\pycharm_matplotlib_backend\sitecustomize.py'>,'site': <module 'site' from 'C:\python38\lib\site.py'>,'foo': <module 'foo' from 'C:\Users\administrator\PycharmProjects\learn\ModelsLearn\foo.py'>}"""
sys.path的应用
@H_404_9@  1.当内存中没有模块路径时,将按照sys.path的路径顺序依次在硬盘中查找。

@H_404_9@  2.Pycharm中的sys.path比Python原生解释器中的sys.path多了三个选项。分别是(第二项,第三项,倒数第一项)

@H_404_9@  3.可使用sys.path.append("模块绝对路径")添加搜索路径。

(sys.path) 当内存中没有模块路径时,将按照sys.path的路径顺序依次在硬盘中查找。Ps:Pycharm执行该脚本时产生的结果模块foo --->['C:\Users\administrator\PycharmProjects\learn\ModelsLearn','C:\Users\administrator\PycharmProjects\learn',# 不存在'D:\Application\PyCharm 2020.1\plugins\python\helpers\pycharm_display',# 不存在'C:\python38\python38.zip','C:\python38\DLLs','C:\python38\lib','C:\python38','C:\python38\lib\site-packages','D:\Application\PyCharm 2020.1\plugins\python\helpers\pycharm_matplotlib_backend' # 不存在]Ps:Python解释器执行该脚本时产生的结果模块foo --->['C:\Users\administrator\PycharmProjects\learn\ModelsLearn','C:\python38\python38.zip','C:\python38\lib\site-packages']"""
包与__init__
@H_404_9@  1.包就是一个包含有__init__.py文件的文件夹。(在Python2中包必须有__init__.py文件,python3中不强制有此要求。)

@H_404_9@  2.包的本质是模块的一种形式。

@H_404_9@  导入包的三步骤:

@H_404_9@    1.产生一个命名空间

@H_404_9@    2.执行__init__.py文件将产生的名字丢到该包的命名空间中

@H_404_9@    3.在当前run.py中拿到一个变量,该变量指向包的命名空间。

 包可以当做一系列模块的集合体(包本身也是一个模块) 自定义包:my_plugin/                #顶级包├── __init__.py     ├── tools          #子包│   ├── __init__.py│   ├── f1.py│   └── f2.py└── m1.py      #子模块foo.pyrun.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...")
使用者 - 包导入强调三点
@H_404_9@  1.关于包相关的导入语句也分为importfrom .. import ..两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如import 顶级包.子包.子模块,但都必须遵循这个原则。但对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。使用者无法使用from . import xxx 的 *** 作,该 *** 作只能在__init__中使用。也就是说对于使用者只能使用绝对导入。

@H_404_9@  2、包A和包B下有同名模块也不会冲突,如A.aB.a来自俩个命名空间

@H_404_9@  3、import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件

 根据包名使用各个功能from ModelsLearn  my_pluginmy_plugin.m1.plugin_m1()my_plugin.tools.f1.tools_f1()my_plugin.tools.f2.tools_f2() 引入某一个单独的文件from ModelsLearn.my_plugin  m1m1.plugin_m1() 引入单独的某一个功能from ModelsLearn.my_plugin.m1  plugin_m1plugin_m1()plugin_m1...tools_f1...tools_f2...plugin_m1...plugin_m1..."""
开发者 - 包内绝对导入
@H_404_9@  . 代表当前文件夹

@H_404_9@  .. 代表上层文件夹

@H_404_9@  包内的绝对导入是指:

@H_404_9@   from 无论何时都跟上后面跟顶级包名(不推荐这么做,万一后期包名需要更改,很麻烦。)

 my_plugin/__init__.py# from . import m1  # 对于开发者来说,只要该文件不是执行文件就可以使用 from . import xxx from . import tools === Ps === : 为了使用者的使用方便。我们可以更加详细的导入(此处导入为绝对导入)from my_plugin.m1  plugin_m1from my_plugin.tools.f1  tools_f1 from my_plugin.tools.f2  tools_f2 run.py 执行文件 使用者可以更简单的使用了 my_pluginmy_plugin.plugin_m1()my_plugin.tools_f1()my_plugin.tools_f2()
开发者 - 包内相对导入
@H_404_9@  使用 from . import xxx

@H_404_9@  其中 . 代表当层文件夹。(注意:包的使用者不能使用from . import xxx的 *** 作,因为对于使用者来说 . 的左边必须是一个包名

@H_404_9@  注意,当使用 .. 的时候不能返回顶级包以上的目录。

@H_404_9@  开发者若想使用 from . import xxx ,则必须在 __init__.py 文件中使用。其余任何地方使用都会引起异常

 my_plugin/__init__.py from . import m1  # 对于开发者来说,只要该文件不是执行文件就可以使用 from . import xxx === Ps === : 使用 from . import xxx 的文件不可被当做执行文件执行。只能被当做模块from .m1 from .tools.f1  tools_f1from .tools.f2 import tools_f2
扩展:循环导入问题及解决方式
@H_404_9@  循环导入是指:

@H_404_9@  模块a中导入模块b,模块b中又导入模块a...

@H_404_9@  循环导入可能导致的问题:

@H_404_9@  命名空间中名字可能加载不全...

@H_404_9@  解决办法:

@H_404_9@    1.导入语句放到最后,保证在导入时,所有名字都已经加载过

@H_404_9@    2.导入语句放到函数中,只有在调用函数时才会执行其内部代码

 === run.py ===结构如下:- foo1.py- foo2.py- run.pyimport foo1  首次导入,执行foo1.py(foo1.x) === foo1.py ===from foo2 import y  首次导入,执行foo2.pyx = 10   根本来不及将x放入foo1的模块命名空间中,就又去执行foo2去了 === foo2.py ===from foo1  foo1 二次导入,不会执行。尝试拿到x,抛出异常。y = 20  由于第一行是导入x。        但是foo1中并没有把x放入foo1模块命名空间中去,        直接抛出异常导致foo2的y也放不进foo2的模块命名空间中去 执行run.py:\python38\python3.exe C:/Users/administrator/PycharmProjects/learn/ModelsLearn/run.pyTraceback (most recent call last):  file C:/Users/administrator/PycharmProjects/learn/ModelsLearn/run.py",line 4,in <module>     foo1  file C:\Users\administrator\PycharmProjects\learn\ModelsLearn\foo1.py y  file C:\Users\administrator\PycharmProjects\learn\ModelsLearn\foo2.py ximportError: cannot import name x' from partially initialized module foo1' (most likely due to a circular ) (C:\Users\administrator\PycharmProjects\learn\ModelsLearn\foo1.py) 可以看到。是 x 抛出的异常,原因上面说的很清楚了,x并没有放入foo1的模块命名空间中去,但是foo2的x尝试将内存指向foo1中的x的内存指向 解决方案1 === run.py === foo1x = 10 先将 x 放入 foo1 的模块命名空间中,就没问题了。y = 20 x  解决方案2 init():     y     x = 10init()  函数定义阶段不会执行,最后调用时x也是已经放在了 foo1 的模块命名空间中。也不会抛出异常 xy = 20init()
扩展:编写规范模块
!/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 = 10y = 20z = 30也就是说,当使用 from ModelsLearn.foo import * 的时候,* 只能拿到 __all__ 中存在的名字。 run.pyfrom ModelsLearn.foo import * 正常访问print(y) print(z)  抛出异常1020Traceback (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"""
@H_69_1301@ 

总结

以上是内存溢出为你收集整理的Python模块与包全部内容,希望文章能够帮你解决Python模块与包所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1190348.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-03
下一篇 2022-06-03

发表评论

登录后才能评论

评论列表(0条)

保存