在实际开发中,需要使用各种各样的包和模块的配合,才能快速完成开发任务。如os、time、Pandas等。这里就涉及到Python模块和包的使用,本节就来讲讲什么是Python模块和包,以及如何使用它们。
P 模块
(1)什么是模块
模块包含可执行语句及函数定义的文件。实际表现上就是一个.py的文本文件,内部包含有代码、函数、类等封装好的程序。也就是说,你写的每一个.py文件都可以是一个模块。并且每一个模块都可以调用其他模块,实现不同模块间的代码重用。
(2)使用模块
通常,使用import 模块名来导入模块,并使用模块名.功能名的方式,使用对应功能。
代码演示,如下:
# 导入os模块import oslst = os.listdir() # 获取当前文件夹下存在的文件、文件夹清单。print(lst) # 打印输出
有的时候模块名很长,我们会起个别名方便调用,需要使用as关键字。此时,使用模块名.功能名的方式,使用对应功能。如下:
# 用as给模块取别名import os as myoslst = myos.listdir() # 起别名后,用别名来调用内部函数、类等功能。print(lst) # 打印输出
上述演示中,将模块导入放到代码的最开始位置。实际应用中可以随意放置,但推荐放置在最开始,方便集中管理。
(3)模块的名字
现在我们有test.py文件,其中的代码如下:
def add(x,y):return x+y# 代码测试print(add(20,30))
可以看到,开发人员在该test.py文件中有测试代码。如果我们将该模块导入到我们的demo.py文件中使用,则会出现如下问题:
import testprint('Hello world')# 输出如下 50Hello world
我们看到,被导入包的代码测试部分被执行了,并输出了内容,这使我们不需要的。实际上,当模块文件运行时,会有一个变量__name__记录该模块的名称。而主运行文件的__name__会固定为__main__,其余文件都是模块名。如下:
test.py文件代码,修改如下:
def add(x,y): return x+y# 代码测试print(add(20,30))print(f'test.py的{__name__=}')
demo.py文件代码,修改如下:
import testprint('Hello world')print(f'demo.py的{__name__=}')
再次执行demo.py文件,结果如下:
50test.py的__name__='test'Hello worlddemo.py的__name__='__main__'
可以看到,只有主运行文件demo.py的__name__是'__main__',而被导入模块__name__是文件名'test'。现在我们不想显示test.py中的内容,需要对test.py代码进行如下修改:
def add(x,y): return x+y# 代码测试if __name__ == '__main__': print(add(20,30)) print(f'test.py的{__name__=}')
再次执行demo.py文件,结果如下:
Hello worlddemo.py的__name__='__main__'
现在所有的数据都是主模块中的信息了,被调用的模块测试内容不再显示。所以在编程中,模块代码调试应写在if __name__ == '__main__':下,防止作为模块调用时的误执行,它可能造成非常长等待时间。
(4)模块搜索路径
上述演示中的test.py和demo.py是放在同一个文件夹下的.py文件,所以很容易导入模块。但实际上,模块导入时,被导入模块不是一定可以被解释器找到的,通常解释器会按照如下顺序搜索模块。
1、当前文件执行目录下搜索模块;
2、环境变量指定的PYTHONPATH路径下搜索;
3、安装包的site-packages目录搜索。
如果都为找到,会爆出错误信息。如下:
# 导入不存在的模块import dsfsdfs# 错误信息Traceback (most recent call last): File "<pyshell#0>", line 1,in <module> import dsfsdfsModuleNotFoundError:No module named 'dsfsdfs'
(5)模块的脚本运行
很多时候,我们会在命令提示符窗口运行python test.py的方式运行该目标文件。有时候,我们需要给模块传递一些参数,会这些写python test.py para1 para2。实际上,这些参数会传入代码中,但需要借助一些模块来解析参数,sys模块就是python默认自带的处理该参数的模块(还有其他模块也可以,不仅仅是sys模块哦)。
demo.py代码,如下:
import sysprint(sys.argv)print(type(sys.argv))
命令提示符输入:python demo.py
# 运行结果为:['demo.py']<class 'list'>
添加一个参数:python demo.py hello
# 运行结果为:['demo.py', 'hello']<class 'list'>
可以看到,sys截获了脚本模式输入的参数,参数为用列表格式呈现,且第一个参数为文件名。虽然脚本模式的参数传递很少用,但其确实是我们必须掌握的方法之一(至少在GUI开发前)。
P 包
Python指导手册中定义包是通过使用“带点号模块名”来构造 Python 模块命名空间的一种方式。例如,模块名 A.B 表示名为 A 的包中名为 B 的子模块。实际上,它就是多个模块的文件夹,但为了让解释器识别它是一个包,必须在文件夹中建立一个为__init__.py的文件(文件为空即可)。
下面是官方提供的包架构:
sound/ 最高层级的包 __init__.py 初始化 sound 包 formats/ 用于文件格式转换的子包 __init__.py wavread.py wavwrite.py aiffread.py aiffwrite.py auread.py auwrite.py ... effects/ 用于音效的子包 __init__.py echo.py surround.py reverse.py ... filters/ 用于过滤器的子包 __init__.py equalizer.py vocoder.py karaoke.py ...
(1)导入包中的子模块
# 用import语法import sound.filters.equalizersound.filters.equalizer() # 包的使用# 用from pkgname import modname语法import sound.filters import equalizerequalizer() # 包的使用
上述两种导入方式,都能将目标模块导入到当前开发的.py文件中使用。但必须用import后面的名称加.功能名来使用,为了避免这种问题,通常会用as起别名方式。
(2)用from pkgname import * 语法的隐患
当我们使用from pkgname import *导入包中所有的模块/功能时,会造成命名空间的破坏。即该模块内的功能如果与原解释器或之前导入包的模块/功能名冲突时,可能造成功能覆盖。
(3)关于__init__.py文件
通常,__init__.py的文件是空的,也就是说不指定子包/模块/功能导入该包时(*导入),所有子包/模块/功能都会一同导入到运行环境中。那如何避免呢?就是要在__init__.py文件中,增加如下一行代码:
__all__ = ["func1", "func2", "func3"]
在__init__.py文件中添加__all__字段后,再次*导入,则只能导入func1、func2、func3三个模块。该字段对应的列表包含的模块是允许*导入的子包/模块/功能的名称。
-------------------------它是数字世界里的一把杀猪刀
却总能巧夺天工
它的世界是纯粹0、1组合
却总能创造无尽幻想
......
本公众号关注数据价值分析、编程学习,将不定期更新社会热点数据分析结果、编程技巧,分享数据分析工具、方法、学习等内容,欢迎有兴趣的小伙伴加入。