1.8 编写与发布自己的包
除了可以在开发环境中或命令提示符环境中直接运行,任何Python程序文件都可以作为模块导入并使用其中的对象,这也是实现代码复用的重要形式。通过Python程序的__name__属性可以识别程序的使用方式,每个Python脚本在运行时都会有一个__name__属性,如果脚本作为模块被导入,则其__name__属性的值被自动设置为模块名;如果脚本作为程序直接运行,则其__name__属性值被自动设置为字符串"__main__"。例如,假设程序hello.py中的代码如下:
def main(): #def是用来定义函数的Python关键字 if__name__=='__main__': #选择结构,识别当前的运行方式 print('This program is run directly.') elif__name__=='hello': #冒号、换行、缩进表示一个语句块的开始 print('This program is used as a module.') main() #调用上面定义的函数
那么通过任何方式直接运行该程序时都会得到下面的结果:
This program is run directly.
而在使用import hello导入该模块时,得到结果如下:
This program is used as a module.
很明显,对于大型软件的开发,不可能把所有代码都存放到一个文件中,那样会使得代码很难维护。对于大型软件系统,可以使用包来管理多个模块。包是Python用来组织命名空间的重要方式,可以看作是包含大量Python程序模块的文件夹。在包的每个子文件夹中都必须包含一个__init__.py文件,该文件可以是一个空文件,仅用于表示当前文件夹是一个包。__init__.py文件的主要用途是设置__all__变量以及执行初始化包所需的代码,其中__all__变量中定义的对象可以在使用“from…import*”时全部被正确导入。
假设有如下结构的包:
sound/ Top-level package __init__.py Initialize the sound package formats/ Subpackage for file format conversions __init__.py wavread.py wavwrite.py effects/ Subpackage for sound effects __init__.py echo.py surround.py reverse.py filters/ Subpackage for filters __init__.py equalizer.py
那么,可以在自己的程序中使用下面的代码导入其中一个模块:
import sound.effects.echo
然后使用完整路径来访问其中的对象,例如:
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)
如果sound\effects\__init__.py文件中有下面一行的代码:
__all__=['echo', 'surround', 'reverse']
那么就可以使用下面的方式来导入__all__变量指定的echo、surround和reverse对象:
from sound.effects import*
然后使用下面的方式来使用其中的成员:
echo.echofilter(input, output, delay=0.7, atten=4)
在组织自己的包时,应避免只有一个__init__.py的文件夹。例如,如果可以用common.py实现同样的功能,就不要使用common\__init__.py这样的结构,除非common.py需要实现的功能非常多,需要分散到多个库中,例如common\database.py、common\net.py、common\user.py等,然后再在common\__init__.py中通过__all__变量指定哪些对象可以导入。
在自己编写模块时,可能需要反复修改代码然后重新导入模块进行测试,此时可以使用imp模块或importlib模块的reload()函数。重新加载模块时要求该模块已经被正确加载过,也就是说,第一次导入和加载模块时不能使用reload()方法。
本节的最后介绍如何把自己的Python包发布到pypi,假设有Python程序文件fastcopytree.py,现在编写一个对应的setup.py文件,内容如下:
from distutils.core import setup setup(name='fastcopytree', version='1.0.0', py_modules=['fastcopytree'], author='dong fuguo', author_email='dongfuguo2005@126.com', url='http://user.qzone.qq.com/306467355/2')
然后在命令提示符环境中执行python setup.py register并选择1进行登录,如果没有pypi账号可以选2先进行注册,登录后再使用python setup.py register-n检查包名是否可用,最后使用python setup.py sdist upload命令把自己的包发布到pypi上去,别人就可以使用pip install fastcopytree来安装这个包了。当然,上面的setup.py程序还有更多的参数可以使用,例如,使用python setup.py bdist_wininst可以创建Windows安装包。