Python项目打包与部署(一):模块与包的概念与关系

当前各类Python教程鲜有涉及Python打包与部署技术,或者讲述过于表面化、片面化。 本人尝试从原理开始,结合实例,并给出标准操作步骤建议,为python编程爱好者提供一份较为详实的Python项目打包与部署参考教程。

本教程其它章节

  • Python项目打包与部署(二): init.py的作用及内容
  • Python项目打包与部署(三):打包与部署的实际操作流程
  • 各类Python项目的项目结构及代码组织最佳实践

虽然 Python 是动态类型编程语言,不需要提前编译。但1个Python项目也是由一组.py文件、数据文件、资源文件等组成,大部分项目还会引用第3方库,也存在依赖管理。因此,python项目管理与其它语言如java,C++是类似的。而构建1个 Python 项目时,模块与包是我们面临的基础概念。

1、模块、包的概念

Python中的模块(Module), 就是一个单独的.py文件,其中包含变量定义,函数定义、类定义、以及其它可执行语句。模块是一个独立的代码单元,可以用解释器直接运行,可以导入到其他模块中。

另一方面,包(Package) 是一个目录中所包含的模块集合。包允许我们将多个相关模块组合在一个公共命名空间下,从而更容易组织和构建我们的代码库。

将代码分解为模块和包可以带来巨大的好处:

  • 可维护性。将代码分解为模块,有助于我们对整个应用程序的独立部分进行更改,而不会影响整个应用程序,因为模块的设计仅用于处理应用程序的一部分。
  • 可重复使用性。这是软件开发的关键部分,我们只需编写一次代码,就可以根据需要在应用程序的许多不同部分中多次使用它。这使我们能够编写干净、简洁的代码。
  • 方便分工合作。模块化代码,团队的不同开发者可以分别承担同一应用程序的不同部分(模块),而不会相互干扰。
  • 可读性。将代码分解为模块和包可以提高代码的可读性。可以很容易地分辨出文件中不同代码的功能。例如,我们可能有一个名为databaseConnection. py的文件:仅从名称上我们就可以知道这个文件处理数据库连接。

2、模块详解

模块包含可执行语句及函数定义。这些语句用于初始化模块,且仅在 import 语句 第一次 遇到模块名时执行。 (文件作为脚本运行时,也会执行这些语句。)

每个模块都有自己的私有命名空间,它会被用作模块中定义的所有函数的全局命名空间。 因此,模块作者可以在模块内使用全局变量而不必担心与用户的全局变量发生意外冲突。 另一方面,如果你知道要怎么做就可以通过与引用模块函数一样的标记法 modname.itemname 来访问一个模块的全局变量。

2.1 创建模块的示例

打开IDE或文本编辑器,创建一个文件,将其命名为sample. py并输入以下代码:

# sample.py# create a variable in the module
sample_variable  = "This is a string variable in the sample.py module"# A function in the module
def say_hello(name):return f"Hello, {name}  welcome to this simple module."# This is another function in the module
def add(a, b):return f"{a} + {b} is = {a+b}"print(sample_variable)
print(say_hello("小明"))
print(add(2, 3))

上面的代码定义了一个名为sample. py的模块。它包含一个名为sample_variable的变量,其值是字符串“This is a string variable in the sample.py module”。此模块还包含两个函数定义。调用时,say_hello ()函数接收一个名称参数,如果我们将一个名称传递给它,它会返回一个欢迎消息。add ()函数返回传递给它的两个数字的和。
虽然模块是用于程序或应用程序的其他部分的,但我们可以单独运行它们。要运行此模块,我们需要在开发环境中安装Python。我们可以使用以下命令在终端上运行它:

python sample.py 

或者

python3 sameple.py

运行结果

This is a string variable in the sample.py module
Hello, 小明  welcome to this simple module.
2 + 3 is = 5

我们可以将其作为独立模块运行,但大多数使用场景下,1个模块通常是导入其他模块或Python 主程序来使用的。因此,要在另一个模块中使用一个模块中的变量、函数和类,我们必须导入该模块。有不同的方法来导入模块,所以让我们来看看如何导入模块

2.2 import 语句

用import module_name 可将另1个模块内容导入到本模块中。如在 another_module.py中使用 import sample

# another_module.pyimport sampleprint(sample.sample_variable)
print(sample.say_hello(“John”))
print(sample.add(2, 3))

上面的代码展示了如何从sample.py模块导入函数,使它们可以在another_module.py中使用。注意,当导入模块时,不需要包括.py扩展名

2.3 使用 from … import … 语句

还可以使用from关键字来导入特定的函数或变量。假设一个模块中定义了大量的函数和变量,我们不想全部使用它们。可以使用from关键字指定要使用的函数或变量:


# another_module.pyfrom sample import addprint(add(10, 4))

上面的代码表明,我们已经从示例模块中专门导入了add()函数。
使用from关键字的另一个好处是,使用导入的函数时,无需对其进行命名或在其前面加上其父模块的名称。这将导致代码更加简洁易读。

2.4 使用 as 关键字

我们可以使用“as”为模块提供别名或备用名称。

有时,我们可能会定义相当长或不可读的模块名称。Python提供了一种为模块导入提供别名的方法,为此,我们将使用as关键字:

# another_module.pyimport sample as spresult = sp.add(5, 5)
print(result)
print(sp.say_hello("Jason"))

这段代码显示了样本模块的导入,其中模块被赋予别名sp。使用sp与调用sample 完全相同。同样可以访问变量和函数。

使用上述三种方法,我们可以在另一个模块中使用一个模块的变量或函数,从而增强了应用程序的可读性,因为我们不需要将代码放在一个文件中。

在命名模块名称时,最好使用小写字母,两个词之间使用_下列线分隔。例如,有一个用于处理数据库连接的模块,可以将其命名为database_connection.py。此外,请记住Python中的名称区分大小写,因此在导入时请确保使用正确的模块名称。

总的来说,使用模块,可以让我们以可读和可维护的方式创建和组织代码。

2.5 在代码中获取模块名

模块内部,通过全局变量 name 可以获取模块名(即字符串), 对前面的例子稍加修改,在sample内部, 以及another_module.py中获取模块名

# another_module.pyimport sampleprint(sample.sample_variable)
print(sample.say_hello(“John”))
print(sample.add(2, 3))
print(__name__)

在another_module.py中,获取sample.py模块名

# another_module.pyimport sample as spresult = sp.add(5, 5)
print(result)
print(sp.say_hello("Jason"))
print(sp.__name__) 

3. 关于包的详解

Python中的包是将相关模块组织到目录中的一种方式。它提供了一种更好的代码组织方式,通常对于完成同1功能,或属于同一组件的模块使用包来进行分组。
包是通过使用“.”点号来表示同1个包、模块、函数(全局变量)的层级关系。例如,模块名称A.B指定了名为A的包中名为B的子模块。

1) Package包, Module模块与文件的关系

Package(包), Module(模块), file(文件) 三者关系,

  • Package由模块组成,相当于Modules 的命名空间
  • Module, 包含功能代码的.py 代码文件也称为 module , 但不能把 config.py , __init__.py称为模块。
    在这里插入图片描述

2) 包与目录的关系

虽然在形式上,可以把1个包理解为1个目录,但并非是包含代码的目录都是包,
在这里插入图片描述

二者区分的关键是, 包目录包含 __init__.py 文件,不包含此文件的不能称之为包目录

Package可以包含 sub package, 但其目录下也必须有__init__.py

使用时,用点号来表示层次关系

mypkg.mymodule.func_1()

3) 导入包,模块, 函数

i假设当前项目,是统一处理声音文件与声音数据的项目。声音文件的格式很多(通常以扩展名来识别,例如:.wav,.aiff,.au),因此,为了不同文件格式之间的转换,需要创建和维护一个不断增长的模块集合。为了实现对声音数据的不同处理(例如,混声、添加回声、均衡器功能、创造人工立体声效果),还要编写无穷无尽的模块流。下面这个分级文件树展示了这个包的架构:

sound/                          Top-level package__init__.py               Initialize the sound packageformats/                  Subpackage for file format conversions__init__.pywavread.pywavwrite.pyaiffread.pyaiffwrite.pyauread.pyauwrite.py...effects/                  Subpackage for sound effects__init__.pyecho.pysurround.pyreverse.py...filters/                  Subpackage for filters__init__.pyequalizer.pyvocoder.pykaraoke.py...

如上一节中提到,包含__init__.py 的目录就是1个包。 因此上述项目中,sound是项目主目录,同时也是1个包,其下还有3个子包, filters, effects, formats 。每个子包下有若干模块。

如何导入子包。
绝对引用:

模块 sound.filters.vocoder需要使用 sound.effects 子包下的echo module, 这样引用:

from sound.effects import echo

相对引用

from . import echo 表示导入当前包下面的echo模块

from … import formats 表示从父目录下导入 formats 子包。

4) 导入第3方包

第3方包,对于经过python社区验证的包,通常也称为库library, 导入方式,根据来源不同分为:

(1) 导入 pip安装的包
按PyPi 方式,即pip安装的第3方包,当导入时, Python解释器会到python安装目录下 Lib/site-packages/ 下查找,如果没找到,会报错。

import numpy
import pandas 

(2) 手工导入第3方包
需要将第3方包绝对路径加入sys.path 变量中。如 第3方包pkg_a路径为/usr/local/pkg_a, 导入及使用示例:


import sys# appending a path
sys.path.append('/usr/local/pkg_a')# importing required module
import pkg_a
from pkg_a import module_a# accessing its content
module_a.foo()

4. 模块搜索路径

常见问题: 在test/ 测试文件导入包与模块时,常常遇到 import error 导入错误问题,其原因是test目录不是项目子包,按默认导入方式,无法找到模块路径。

在.py模块文件中,导入其它模块,如 spam时,解释器首先搜索python内置模块。这些模块名称列在sys.builtin_module_names中。如果找不到,它将在变量sys.path给定的目录列表中搜索名为spam.py的文件。
sys.path从以下位置初始化:

  • 命令行直接运行的.py脚本所在的目录(或未指定文件时的当前目录)。
  • PYTHONPATH (内容是目录列表)。
  • python安装目录下的 Lib/site-packages 子目录。
>>> import sys
>>> sys.path
['',
'C:\\opt\\Python36\\python36.zip',
'C:\\opt\\Python36\\DLLs',
'C:\\opt\\Python36\\lib',
'C:\\opt\\Python36',
'C:\\Users\\NanoDano\\AppData\\Roaming\\Python\\Python36\\site-packages',
'C:\\opt\\Python36\\lib\\site-packages',
'C:\\opt\\Python36\\lib\\site-packages\\win32',
'C:\\opt\\Python36\\lib\\site-packages\\win32\\lib',
'C:\\opt\\Python36\\lib\\site-packages\\Pythonwin']

更改sys.path的3种方式:

(1) appending a path

sys.path.append(``'C:/Users/Vanshi/Desktop'``)

(2) sys.path 初始化时会读python的系统变量 PYTHONPATH 。可以在启动脚本中修改PYTHONPATH, 语法与 环境变量path相同

set PYTHONPATH=C:\pypath1\;C:\pypath2\
python -c "import sys; print(sys.path)"
# Example output
['', 'C:\\pypath1', 'C:\\pypath2', 'C:\\opt\\Python36\\python36.zip', 'C:\\opt\\Python36\\DLL

set 变量名=值 是临时添加,关闭terminal 后则失效。

永久性添加可修改环境变量, 应小心使用
setx ENV_NAME env_value,

如:

setx -m PATH “%PATH%;C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin”

Linux中添加环境变量命令

export PYTHONPATH=‘/some/extra/path’

(3) 使用site模块来修改sys.path

在程序代码中修改sys.path 变量, 这样系统启动时加载它,就可以找到相应模块了。

import site
import syssite.addsitedir('/the/path')  # Always appends to end
print(sys.path)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/69047.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【【萌新的STM32的学习--非正点原子视频的中断设计思路】】

萌新的STM32学习–非正点原子视频的中断设计思路 我们分析而言 我们对于PA0 的设计就从此而来 对于边沿触发的选择我们已经有所了解了 我们下拉,但是当我们摁下开关的时候 从0到1 导通了 所以这个是下拉 上升沿触发 而对于KEY0 我们摁下是使得电路从原来悬空高阻态…

算法通关村第10关【黄金】| 归并排序

归并排序(Merge Sort)是一种常见的基于比较的排序算法,它的主要思想是分而治之(Divide and Conquer)。它的核心思想是将一个大的问题分解为小的子问题,解决子问题,然后将它们合并(me…

开启EMQX的SSL模式及SSL证书生成流程

生成证书 首先:需要安装Openssl 以下是openssl命令 生成CA证书 1.openssl genrsa -out rootCA.key 2048 2.openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 -subj "/CCN/STShandong/Ljinan/Oyunding/OUplatform/CNrootCA" -out ro…

模型的保存加载、模型微调、GPU使用及Pytorch常见报错

序列化与反序列化 序列化就是说内存中的某一个对象保存到硬盘当中,以二进制序列的形式存储下来,这就是一个序列化的过程。 而反序列化,就是将硬盘中存储的二进制的数,反序列化到内存当中,得到一个相应的对象&#xff…

理解 std::thread::join

C多线程并发编程入门(目录) 本文用最简单易懂的实际案例,讲清楚了 join 的实际内涵,保证你过目不忘。 Hello join 示例 join 函数是我们接触C多线程 thread 遇到的第一个函数。 比如: int main() {thread t(f);t.…

哈希的应用——位图

文章目录 前言1. 面试题思考2. 位图2.1 位图的概念2.2 思路讲解及代码实现结构定义构造函数set和reset接口实现set和reset测试观察test接口实现test接口测试思考 3. 位图的应用习题1习题2习题3 4. 总结5. 源码5.1 bitset.h5.2 Test.c 前言 前面的文章里我们学习了哈希表&#x…

赞奇科技参与华为云828 B2B企业节,云工作站入选精选产品解决方案

8月27日,由华为云携手上万家伙伴共同发起的第二届 828 B2B 企业节拉开帷幕,围绕五大系列活动,为万千中小企业带来精细化商机对接。 聚焦行业数字化所需最优产品,举办超1000场供需对接会,遍及20多个省100多个城市&…

Python小知识 - 使用Python进行数据分析

使用Python进行数据分析 数据分析简介 数据分析,又称为信息分析,是指对数据进行综合处理、归纳提炼、概括总结的过程,是数据处理的第一步。 数据分析的目的是了解数据的内在规律,为数据挖掘,并应用于商业决策、科学研究…

运行速度高达1.8GHz可编程采集网关

今天介绍下BL304这个设备。嵌入式ARM控制器BL304系列是一款专为工业控制领域设计的坚固型工控设备。它采用NXP公司的处理器I.MX8M Mini四核64位处理器,搭配四核 Cortex-A53单核Cortex-M4构架,运行速度高达1.8GHz,具有高度的稳定性和可靠性。 …

从0到1学会Git(第二部分):Git的本地操作和管理

写在前面:本文介绍了在本地仓库进行文件的处理以及本地的合并等操作。 前置知识:文件可以处在三个区域,分别为工作区,暂存区和本地仓库,我们此文的目标即是将文件存储在本地仓库中。我们可以将文件的区域理解为,cpu中&#xff0c…

计算机视觉主要任务

计算机视觉:使用计算机及相关设备对生物视觉的一种模拟。 主要包含6大任务,图像分类,目标检测,目标跟踪,语义分割,实例分割,影像重构。 图像分类:根据图像信息中所反映的不同特征&am…

数据结构与算法复杂度介绍

目录 一、基本概念 二、时间复杂度 【2.1】时间复杂度概念 【2.2】大O的渐进表示法 【2.3】举例时间复杂度计算 三、空间复杂度 一、基本概念 数据结构:相互之间存在一种或者多种特定关系的数据元素的集合。在逻辑上可以分为线性结构,散列结构、树…

Redis List类型命令 - Set类型命令 - SortedSet类型命令

目录 List类型 什么是双向链表呢? List类型的特征: List的常用命令 LPUSH和RPUSH的区别: LPOP和RPOP的区别: LPUSH和RPUSH的使用 LPOP和RPOP的使用 LRANGE key star end:返回一段距离范围内所有的元素 BLPOP…

最小生成树Kruskal、Prim算法C++

什么是最小生成树 连通图: 在无向图中,若从顶点v1到顶点v2有路径,则称顶点v1和顶点v2是连通的。如果图中任意一对顶点都是连通的,则称此图为连通图。 生成树: 一个连通图的最小连通子图称作为图的生成树。有n个顶点的…

Pytorch 的基本概念和使用场景介绍

文章目录 一、基本概念1. 张量(Tensor)2. 自动微分(Autograd)3. 计算图(Computation Graph)4. 动态计算图(Dynamic Computation Graph)5. 变量(Variable) 二、…

【用unity实现100个游戏之8】用Unity制作一个炸弹人游戏

文章目录 前言素材开始一、绘制地图二、玩家设置三、玩家移动四、玩家四方向动画运动切换 五、放置炸弹六、生成爆炸效果七、墙壁和可破坏障碍物的判断八、道具生成和效果九、玩家死亡十、简单的敌人AI十一、简单敌人AI十二、随机绘制地图十三、虚拟摇杆 最终效果待续源码完结 …

2023年行研行业研究报告

第一章 行业概述 1.1 行研行业 行业定义为同一类别的经济活动,这涉及生产相似产品、应用相同生产工艺或提供同类服务的集合,如食品饮料行业、服饰行业、机械制造行业、金融服务行业和移动互联网行业等。 为满足全球金融业的需求,1999年8月…

Linux之autofs自动挂载服务

目录 Linux之autofs自动挂载服务 产生原因 安装 配置文件分析 文件路径 作用 etc/auto.master文件内容格式 挂载参数 案例 案例1 --- 服务器创建共享目录,客户端实现自动挂载 案例2 --- 自动挂载光盘 Linux之autofs自动挂载服务 产生原因 在一般NFS文件系…

$attrs,$listeners

vue实现组件通信的方式有: 父子通信 父组件向子组件传递通过props定义各个属性来传递,子组件向父组件传递通过$emit触发事件 ref也可以访问组件实例跨级通信 vuex bus provide / inject $attrs / $listeners解释 $attrs / $listeners $attrs 将父组件中…