python代码的入口点

https://amir.rachum.com/blog/2017/07/28/python-entry-points/

随心所欲翻译版本.侵删.

这篇文章将会聊聊python代码中的入口点.很多人可能知道,入口点一般会放在文件中,经过打包后可以作为命令行使用,不过很少有人会去用它.接下来,我将会介绍如何使用入口点生成python包,之后就可以让别人在代码中或者命令行下使用.

安装过python包的都知道使用,就是定义了你自己开发的包的相关信息,然后可以打包上传到python的包管理中心供别人下载.而入口点可以让包作为命令行工具使用.

Snek,Inc.

恭喜你!你刚刚被任命为”snek半导体和软件公司”的CEO,作为CEO,你的第一个工作是让员工开发出snek的原型系统,很快,工程师就做出来了,它是一个python脚本,:

ascii_snek ="""\ --..,_ _,.--. `'.'. .'`__ o `;__. '.'. .'.'` '---'` ` '.`'--....--'`.' `'--....--'`"""

defmain(): print(ascii_snek)

if__name__ =='__main__': main()

在公司产品发布的那一天,你演示了这个原型系统,运行很顺利:

$ python snek.py --..,_ _,.--. `'.'. .'`__ o `;__. '.'. .'.'` '---'` ` '.`'--....--'`.' `'--....--'`

SaaS—Snek as a Service

不幸的是,用户不会使用python,他们只想在电脑的命名行下直接使用Snek的服务,于是工程师们加班加点作出了下一个版本,让snek在安装时自动生成控制台脚本,这样就可以在命令行下运行了.他们是怎么做的?只需要在 脚本中包含包名,依赖等信息,像下面这样:

下面的代码就是指定了应该从snek脚本的main函数开始执行.

fromsetuptoolsimportsetupsetup( name='snek', entry_points={

'console_scripts': [

'snek = snek:main', ], })

工程师说,控制台脚本就是特殊的入口点,在你的包被别人安装时,读取其中的内容并生成某些脚本文件.现在,让我们从源代码中安装(当然你可以发布为python库,让别人使用pip下载安装):

$ python setup.py developrunning developrunning egg_infowriting snek.egg-info\PKG-INFOwriting dependency_links to snek.egg-info\dependency_links.txtwriting entry points to snek.egg-info\entry_points.txtwriting top-level names to snek.egg-info\top_level.txtreading manifest file'snek.egg-info\SOURCES.txt'writing manifest file'snek.egg-info\SOURCES.txt'running build_extCreating c:\program files (x86)\py36-32\lib\site-packages\snek.egg-link (link to .)snek0.0.is already the active versionineasy-install.pthInstalling snek-script.py script to C:\Program Files (x86)\Py36-32\ScriptsInstalling snek.exe script to C:\Program Files (x86)\Py36-32\ScriptsInstalling snek.exe.manifest script to C:\Program Files (x86)\Py36-32\ScriptsInstalled c:\users\rachum\notebooksProcessing dependenciesforsnek==0.0.Finished processing dependenciesforsnek==0.0.

在公司的年度产品会上,你展示了这个amazing的产品:

$ snek --..,_ _,.--. `'.'. .'`__ o `;__. '.'. .'.'` '---'` ` '.`'--....--'`.' `'--....--'`

Snek for Everyone

没有人不喜欢Snek,公司的IPO超过了60亿美元.有些高级用户希望为他们量身定制高级的版本.工程师又加班加点做了出来:

"""Print an ASCII Snek.Usage: snek [--type=TYPE]"""

importdocoptnormal_snek ="""\ --..,_ _,.--. `'.'. .'`__ o `;__. '.'. .'.'` '---'` ` '.`'--....--'`.' `'--....--'`"""

fancy_snek ="""\ _,..,,,_ '``````^~"-,_`"-,_ .-~c~-. `~:. ^-. `~~~-.c ; `:. `-, _.-~~^^~:. `. ; _,--~~~~-._ `:. ~. .~ `. .` ;' .:` `: `:. ` _.:-,. `. .' .: :' _.-~^~-. `. `..' .: `. ' : .' _:' .-' `. :. .: .'`. : ; : `-' .:' `. `^~~^` .:. `. ; ; `-.__,-~ ~-. ,' ': '.__.` :' ~--..--' ':. .:' ':..___.:'"""

defget_sneks():

return{

'normal': normal_snek,

'fancy': fancy_snek, }

defmain(): args = docopt.docopt(__doc__) snek_type = args['--type']or'normal'print(get_sneks()[snek_type])

if__name__ =='__main__': main()

他们加了一个豪华版的Snek,这让高级用户特别开心.

$ snek --..,_ _,.--. `'.'. .'`__ o `;__. '.'. .'.'` '---'` ` '.`'--....--'`.' `'--....--'`$ snek --type fancy _,..,,,_ '``````^~"-,_`"-,_ .-~c~-. `~:. ^-. `~~~-.c ; `:. `-, _.-~~^^~:. `. ; _,--~~~~-._ `:. ~. .~ `. .` ;' .:` `: `:. ` _.:-,. `. .'.: :' _.-~^~-. `. `..'.: `.' : .'_:' .-'`. :. .: .'`. : ; : `-'.:' `. `^~~^` .:. `. ; ; `-.__,-~ ~-. ,'': '.__.` :' ~--..--'':. .:'':..___.:'

Snek International Community

全球数百万人都在使用snek,人们对snek不同版本的需求越来越高,而且一些snek的专业用户(程序员)要求snek可以定制,他们想开发自己的snek版本.

"""Print an ASCII Snek.Usage: snek [--type=TYPE]"""

importdocopt

importpkg_resourcesnormal_snek ="""\ --..,_ _,.--. `'.'. .'`__ o `;__. '.'. .'.'` '---'` ` '.`'--....--'`.' `'--....--'`"""

fancy_snek ="""\ _,..,,,_ '``````^~"-,_`"-,_ .-~c~-. `~:. ^-. `~~~-.c ; `:. `-, _.-~~^^~:. `. ; _,--~~~~-._ `:. ~. .~ `. .` ;' .:` `: `:. ` _.:-,. `. .' .: :' _.-~^~-. `. `..' .: `. ' : .' _:' .-' `. :. .: .'`. : ; : `-' .:' `. `^~~^` .:. `. ; ; `-.__,-~ ~-. ,' ': '.__.` :' ~--..--' ':. .:' ':..___.:'"""

defget_sneks(): sneks = {

'normal': normal_snek,

'fancy': fancy_snek, }

forentry_pointinpkg_resources.iter_entry_points('snek_types'): sneks[entry_point.name] = entry_point.load()

returnsneks

defmain(): args = docopt.docopt(__doc__) snek_type = args['--type']or'normal'print(get_sneks()[snek_type])

if__name__ =='__main__': main()

他们增加了snek的基础架构,当snek运行时,使用被称作的入口点注册其他类型的snek,这样就能动态的在控制台输出不同的snek版本.

具体来说,中的遍历所有注册到入口点的snek名,然后加入snek版本中.于是,开发者们加入了一个可爱版本的snek,命名为:

cute_snek =r""" /^\/^\ _|__| O| \/ /~ \_/ \ \____|__________/ \ \_______ \ `\ \ \ | | \ / / \ / / \ / / \ \ / / \ \ / / _----_ \ \ / / _-~ ~-_ | | ( ( _-~ _--_ ~-_ _/ | \ ~-____-~ _-~ ~-_ ~-_-~ / ~-_ _-~ ~-_ _-~ ~--______-~ ~-___-~"""

如何找到这个可爱版本的snek呢?像下面这样定义:

代码中指定了从脚本寻找cute_snek.

fromsetuptoolsimportsetupsetup( name='cute_snek', entry_points={

'snek_types': [

'cute = cute_snek:cute_snek', ], })

然后像之前一样打包:

$cdcute_snek && python setup.py developrunning developrunning egg_infowriting cute_snek.egg-info\PKG-INFOwriting dependency_links to cute_snek.egg-info\dependency_links.txtwriting entry points to cute_snek.egg-info\entry_points.txtwriting top-level names to cute_snek.egg-info\top_level.txtreading manifest file'cute_snek.egg-info\SOURCES.txt'writing manifest file'cute_snek.egg-info\SOURCES.txt'running build_extCreating c:\program files (x86)\py36-32\lib\site-packages\cute-snek.egg-link (link to .)cute-snek0.0.is already the active versionineasy-install.pthInstalled c:\users\rachum\cute_snekProcessing dependenciesforcute-snek==0.0.Finished processing dependenciesforcute-snek==0.0.

现在我们就能在命令行下成功的运行这个可爱版本的snek,这是从中动态加载的:

$ snek --type cute /^\/^\ _|__| O| \/ /~ \_/ \ \____|__________/ \ \_______ \ `\ \ \ | | \ / / \ / / \ / / \ \ / / \ \ / / _----_ \ \ / / _-~ ~-_ | | ( ( _-~ _--_ ~-_ _/ | \ ~-____-~ _-~ ~-_ ~-_-~ / ~-_ _-~ ~-_ _-~ ~--______-~ ~-___-~

既然cute_snek可以动态的加载,那么所有类型的snek应该都可以动态加载,于是工程师们又修改了代码:

所有的snek都从中加载.

fromsetuptoolsimportsetupsetup( name='cute_snek', entry_points={

'snek_types': [

'cute = cute_snek:cute_snek',

'normal = snek:normal_snek',

'fancy = snek:fancy_snek', ], })

# 同时修改之前文件中的get_sneks()函数:

defget_sneks():

#sneks = {# 'normal': normal_snek,# 'fancy': fancy_snek,#}# 将snek修改为空字典snek = {}

forentry_pointinpkg_resources.iter_entry_points('snek_types'): sneks[entry_point.name] = entry_point.load()

returnsneks

现在重新打包snek:

$ python setup.py developrunning developrunning egg_infowriting snek.egg-info\PKG-INFOwriting dependency_links to snek.egg-info\dependency_links.txtwriting entry points to snek.egg-info\entry_points.txtwriting top-level names to snek.egg-info\top_level.txtreading manifest file'snek.egg-info\SOURCES.txt'writing manifest file'snek.egg-info\SOURCES.txt'running build_extCreating c:\program files (x86)\py36-32\lib\site-packages\snek.egg-link (link to .)snek0.0.is already the active versionineasy-install.pthInstalling snek-script.py script to C:\Program Files (x86)\Py36-32\ScriptsInstalling snek.exe script to C:\Program Files (x86)\Py36-32\ScriptsInstalling snek.exe.manifest script to C:\Program Files (x86)\Py36-32\ScriptsInstalled c:\users\rachum\notebooksProcessing dependenciesforsnek==0.0.Finished processing dependenciesforsnek==0.0.

大功告成!!!

$ snek --..,_ _,.--. `'.'. .'`__ o `;__. '.'. .'.'` '---'` ` '.`'--....--'`.' `'--....--'`$ snek --type fancy _,..,,,_ '``````^~"-,_`"-,_ .-~c~-. `~:. ^-. `~~~-.c ; `:. `-, _.-~~^^~:. `. ; _,--~~~~-._ `:. ~. .~ `. .` ;' .:` `: `:. ` _.:-,. `. .'.: :' _.-~^~-. `. `..'.: `.' : .'_:' .-'`. :. .: .'`. : ; : `-'.:' `. `^~~^` .:. `. ; ; `-.__,-~ ~-. ,'': '.__.` :' ~--..--'':. .:'':..___.:'$ snek --type cute /^\/^\ _|__| O| \/ /~ \_/ \ \____|__________/ \ \_______ \ `\ \ \ | | \ / / \ / / \ / / \ \ / / \ \ / / _----_ \ \ / / _-~ ~-_ | | ( ( _-~ _--_ ~-_ _/ | \ ~-____-~ _-~ ~-_ ~-_-~ / ~-_ _-~ ~-_ _-~ ~--______-~ ~-___-~

到此为止,你应该大概知道了如何使用python中的入口点了吧.

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180403A1MG4X00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励