python的包机制
⑴ Rez入门教程(四): python包与环境构建
Rez入门教程(四): Python包与环境构建
对于新开发者,本教程旨在加速Rez的部署和包配置学习,特别针对Windows用户,但同样适用于Linux系统。这一节将深入讲解如何创建Python包,使其支持在构建过程中执行Python命令。
首先,编写一个包体构建脚本,如package.py。其中,`requires`参数定义了构建时所需的依赖,Rez会自动在安装时绑定这些依赖。通过`build_command`,我们可以在包内运行Python脚本,如hello_world.py。执行构建后,可以看到hello_world.py脚本的指令被成功执行。
Rez环境中,Python程序的运行依赖于Rez而非系统环境变量。在初次安装Rez时,这些环境变量已经设置。进一步理解,我们构建另一个包含init.py, python_env.py的包。在构建过程中,_init_.py脚本被调用,这个过程涉及到两个关键的环境变量:
- 一个指向包体源代码的环境变量,即包文件结构的根目录。
- 另一个表示构建后包存放位置的环境变量,即构建完成后的包体位置。
通过观察这些环境变量,我们可以深入理解Rez的运行机制和包的构建流程。
⑵ 如何编写高质量的python程序
写出规范的代码是写出高质量代码的第一步,并且有助于培养仔细的习惯。
为了培养规范写代码的习惯,可以安装flake8这个工具,它不仅可以检查代码风格是否符合官方建议(PEP8),而且还能找出潜在的隐患(用Pyflakes做语法分析),更逆天的是还能检测到你有些函数写的太复杂(代码圈复杂度)了,更更逆天的是可以设置git commit之前必须通过这些检查。
当然具体操作需要根据自己的项目进行一些定制,比如可以忽略E501,W293。
空白项目模版
好的开始是成功的一半,写python代码就从pyempty开始吧。
在github上看一下那些经典的项目,web.py,flask, pep8,他们的项目目录都很规范,综合借鉴了一些项目的特点,我写了这个pyempty项目。
1.README.md 这里写你项目的简介,quick start等信息,虽然distutils要求这个文件没有后缀名,但github上如果后缀是.md的话可以直接转换成html显示。
2.ChangeLog.txt 该文件存放程序各版本的变更信息,也有一定的格式,参考web.py的ChangeLog.txt
3.LICENES.txt 这里存放你项目使用的协议,不要编写自己的协议。
4.requirements.txt 如果你的项目需要依赖其它的python第三方库,在这里一行一个写出来,可能pip install的时候能自动帮你安装
5.setup.py 安装脚本,后面详细介绍
6.docs 里面存放你的项目文档,如概要设计,详细设计,维护文档,pydoc自动生成的文档等,强烈推荐大家使用MarkDown格式编写文档
7.src 这个目录里存放项目模块的主要代码,尽量不要把模块目录直接放到根目录,模块代码目录可以在setup.py里指定的
8.tests 这个目录存放所有单元测试,性能测试脚本,单元测试的文件确保以test_做前缀,这样distutils会自动打包这些文件,并且用python -m unittest discover -s ./ -p 'test_*.py' -v 可以直接执行这些测试
单元测试
Martin Fowler:"在你不知道如何测试代码之前,就不该编写程序。而一旦你完成了程序,测试代码也应该完成。除非测试成功,你不能认为你编写出了可以工作的程序。"
我们有很多理由不写单元测试,归根结底是懒,虽然代码大全上说:
大部分研究都发现,检测比测试的成本更小。NASA软件工程实验室的一项研究发现,阅读代码每小时能够检测出来的缺陷要比测试高出80%左右(Basili and Selby 1987)。后来,IBM的一项研究又发现,检查发现的一个错误只需要3.5个工作时,而测试则需要花费15-25个工作时(Kaplan 1995)。
但是单元测试还是让别人相信你的代码有很高质量的最有力证据。
好了,请详细阅读:
深入python3.0: 单元测试-2.x也适用
Unit testing framework 不完整中文版
文档
敏捷开发不是提倡什么文档也不写,没有文档就没有传承和积累,轮岗或新人接手任务就会遇到很大的麻烦,所以我决定每个项目最少要写以下文档:
1.nalysis.model.md 概要设计文档,不同于README.md文件,该文档应该写于项目开发之前,把项目有哪些功能,大概分几个模块等项目整体概述信息写一下。
2.design.model.md 详细设计文档,不用太详细,至少把项目依赖哪些东西,谁依赖这个项目,重要算法流程描述,代码整体结构等写出来。
3.maintain.md 维护文档,这个我觉得最重要,你的服务都记录哪些日志,需要监控哪些业务指标,如何重启,有哪些配置项等,没这些东西,你的项目很难运维。
上面这些文档都是项目全局性的文档,不适合写在docstring或注视里,所以要有单独的文档。
打包
python有专门的模块打包系统distutils,你可以用这套机制把你的代码打包并分发到Pypi上,这样任何人都可以用pip或easy_install安装你的模块。
如果你开发的是内部项目,还可以用mypypi架设私有的pypi,然后把项目的大的版本更新发布到内部的pypi上,配置管理人员和运维人员可以很方便的从pypi上拉取代码安装到测试环境或生产环境。
发布大版本的时候要给版本命名及编写ChangeList,可以参考Git Pro的相关章节,主要记住以下几个命令。
git tag -a v0.1 -m 'my test tag' #给大版本命名,打Tag
git describe master #给小版本命名,Git将会返回一个字符串,由三部分组成:最近一次标定的版本号,加上自那次标定之后的提交次数,再加上一段SHA-1值
git shortlog --no-merges master --not v0.1 #生成版本简报,ChangeList
python有自己的打包机制,所以一般不要用git archive命令。
当然大版本管理用pypi管理比较合适,小的bug fix,紧急上线等好多公司都是用git直接从生产环境拉代码更新,因为git,svn等可以很方便的撤销某次更新,回滚到某个位置。
如何管理好大版本上线和小的紧急上线,我还没理清思路,欢迎大家参与讨论。
关于打包,请阅读如下链接:
Python 打包指南
深入Python3.0:打包 Python 类库
python打包:分发指定文件
出自:http://developer.51cto.com/art/201209/356603.htm
⑶ 深入了解Python的import机制
Python中官方定义,导入机制允许代码在不同模块间访问,通过导入过程实现。日常开发中,我们常使用`from xxx import xxx`或`import xx`导入包。包中常包含`__init__.py`文件,引发好奇。本文将深度探讨模块/包与导入机制的加载、搜索过程,以Python 3.9.1文档为参考。
模块定义为逻辑上组织Python代码的载体,本质是`.py`文件,通过`__name__`全局变量获取模块名,模块内可执行语句仅执行一次,通常在模块初始化时。
包则是通过层次结构组织模块,可视为文件系统目录中的文件,包可以包含子包和模块。包与模块并非必须来自文件系统,实质上,任何具有`__path__`属性的模块被视为包。包分为常规包和命名空间包,常规包包含`__init__.py`文件,命名空间包由部分构成,可位于不同位置或网络中。
导入系统允许模块间访问代码,`import`语句是最常用方式,也可通过`importlib.import_mole()`或`__import__()`实现。`import`操作包括搜索和绑定模块。搜索定义为对`__import__()`函数调用,返回值绑定当前作用域。`__import__()`直接调用仅执行搜索和创建模块,可能引发副作用,如更新缓存。
模块搜索路径包含内置模块查找、sys.path目录查找。导入`happy`时,首先检查内置模块,未找到则查找sys.path列表。sys.path初始值来源于文件系统路径或环境变量,推荐避免模块名与标准库同名。扩展搜索路径可通过`.pth`文件,添加绝对路径后放入特定位置。
深入搜索涉及缓存、查找器和加载器。缓存`sys.moles`用于存储已导入模块,查找器确定模块位置,加载器执行模块加载。导入机制中,缓存`sys.moles`后,查找器`finder`确定模块位置,通过`loader`加载模块。查找器`finder`返回`mole spec`,`loader`执行模块。
导入钩子用于扩展导入机制,分为元路径钩子和导入路径钩子。元路径钩子在导入开始时被调用,处理系统路径、内置模块等,通过`sys.meta_path`注册。导入路径钩子处理`sys.path`或`package.__path__`,通过`sys.path_hooks`注册。
导入加载机制涉及`loader`对象执行模块,`mole spec`封装模块导入信息,通过`mole.spec`公开。命名空间包不再依赖`__init__.py`文件,而是通过`__path__`属性实现。基于元路径查找器`PathBasedFinder`遍历`sys.path`查找模块,通过缓存`sys.path_importer_cache`减少重复匹配。路径条目查找器`PathEntryFinder`用于解析特定路径条目,实现模块导入。
综上所述,Python的导入机制通过模块、包的组织,以及导入系统的搜索、加载过程实现模块间代码访问。深入理解这些机制有助于优化代码结构和导入效率。