The easy (and nice) way to do CLI apps in Python——github源碼 為一個(gè)簡單的python命令行應(yīng)用的基本結(jié)構(gòu)。
我們有一些方法可以做出Python的命令行式app。我試過它們骚秦,不過它們大都有自己的痛點(diǎn)和煩惱灼伤。所以我到社區(qū)里去尋找一種更好的方法策添。
什么是CLI恋捆?
CLI 意味著命令行界面(command line interface)棵逊。它是一類用命令行/終端調(diào)用的app万矾。作為開發(fā)人員悼吱,更是一個(gè)少用鼠標(biāo),多用鍵盤黨良狈,我一直使用CLI應(yīng)用后添。當(dāng)我需要一些為自己服務(wù)的定制軟件時(shí),CLI就能滿足我的需求们颜,而python是一門能夠快速生產(chǎn)CLI應(yīng)用的偉大語言吕朵。
文件系統(tǒng)結(jié)構(gòu)
pycli/
├── README.md
├── install.sh
├── pycli
├── __init__.py
├── __main__.py
├── classmodule.py
└── funcmodule.py
└── setup.py
正如你所見,該項(xiàng)目的根目錄被我命名為pycli
窥突。該應(yīng)用也將在setup.py
中被設(shè)置為以名稱pycli
被調(diào)用努溃。
CLI子目錄
在該CLI根目錄下只有一個(gè)子目錄。它的名字和CLI應(yīng)用同名阻问,但是在更復(fù)雜的CLI應(yīng)用中梧税,你需要有多個(gè)包。每個(gè)子目錄是每個(gè)包的容器。在我的簡單案例中第队,只有單個(gè)包哮塞,也就是單個(gè)子目錄。
__init__.py
這個(gè)文件(空文件)放在這里是告訴Python這個(gè)目錄是一個(gè)包凳谦。它可以是空的忆畅,只是做個(gè)關(guān)于包的簡單提示;也可以包含實(shí)際代碼尸执,在包自身初始化時(shí)會被運(yùn)行家凯。
__main__.py
這是重要部分,是我們CLI應(yīng)用的入口如失,根目錄下的setup.py
中的安裝配置會指示它绊诲。這里只是放些簡單的代碼在這里表明它起作用了。
import sys
from .classmodule import MyClass
from .funcmodule import my_function
def main():
# 以下內(nèi)容中的參數(shù)解析方式并不好褪贵,這里只是為了簡單
# 最好使用argparse或者click模塊做這方面的工具
print('in main')
args = sys.argv[1:]
print('count of args :: {}'.format(len(args)))
for arg in args:
print('passed argument :: {}'.format(arg))
my_function('hello world')
my_object = MyClass('Thomas')
my_object.say_name()
#以下無關(guān)于包安裝掂之,只是為了本文件的測試
if __name__ == '__main__':
main()
上面所做的只是引入一些其它模塊,分析被傳入CLI的命令行參數(shù)脆丁,然后使用導(dǎo)入模塊的成員(一個(gè)簡單的函數(shù)和一個(gè)簡單的類)世舰。
classmodule.py
一個(gè)被導(dǎo)入__main__.py
并被實(shí)例化的極簡的類(也沒啥用)。這里是為了說明如何從同一個(gè)包里的其它模塊中引入一個(gè)類偎快。
class MyClass():
def __init__(self, name):
self.name = name
def say_name(self):
print('name is {}'.format(self.name))
funcmodule.py
classmodule.py
展示如何為__main__.py
定義一個(gè)可以導(dǎo)入的類冯乘,funcmodule.py
則展示了如何定義一個(gè)簡單的函數(shù)讓__main__.py
導(dǎo)入并調(diào)用。
def my_function(text_to_display):
print('text from my_function :: {}'.format(text_to_display))
setup.py
現(xiàn)在讓我們回到CLI源碼的根目錄晒夹。setup.py
文件將所有東西聯(lián)系在一起并告訴Python如何處理它們裆馒。
from setuptools import setup
setup(
name = 'pycli',
version = '0.1.0',
packages = ['pycli'],
entry_points = {
'console_scripts': [
'pycli = pycli.__main__:main'
]
})
第一眼看上去可能覺得很復(fù)雜。但是全部工作只是從setuptools
庫導(dǎo)入setup
函數(shù)丐怯,并傳入一些參數(shù)來調(diào)用它喷好。其中大部分是不言自明的。packages
參數(shù)是根目錄下所有包的列表读跷。
entry_points
是重要部分梗搅。它用字符串表明當(dāng)前應(yīng)用該以什么名稱被調(diào)用,以及被運(yùn)行時(shí)真正調(diào)用的是什么效览。這里寫的是pycli = pycli.__main__:main
无切,也就是說,該應(yīng)用被叫做pycli
丐枉,當(dāng)執(zhí)行該應(yīng)用時(shí)它會調(diào)用pycli
包下的__main__
模塊的main
函數(shù)哆键。就是這樣!
install.sh
安裝你的Python CLI應(yīng)用的最佳方式是使用pip
(python3則是pip3
)瘦锹。在CLI源碼的根目錄下運(yùn)行pip3 install .
將會使用setup.py
作為"指令"安裝這個(gè)應(yīng)用籍嘹,同樣闪盔,使用pip3 uninstall pycli
會卸載這個(gè)應(yīng)用。
寫在腳本中即是
pip3 uninstall pycli -y # 標(biāo)簽-y意味著確認(rèn)卸載
pip3 install .
這樣會安裝到python Lib的site-packages中辱士,或者更簡潔的是
pip3 install -e .
這樣是在當(dāng)前根目錄下生成了egg-info文件泪掀,而在site-packages文件夾中生成一個(gè)egg-link鏈接,如下圖
這樣颂碘,就可以直接運(yùn)行install.sh
以現(xiàn)有的CLI源碼來更新原來的CLI應(yīng)用了异赫。
總結(jié)
掌握了簡單的流程,用python編寫命令行程序是簡潔高效的凭涂。使用結(jié)果如首圖贴妻。