命令行構(gòu)建 Python 目錄樹生成器(命令行創(chuàng)建)

      網(wǎng)友投稿 1268 2022-05-30

      目錄

      演示:Python 中的目錄樹生成器工具

      項(xiàng)目概況

      布置項(xiàng)目

      概述解決方案

      組織代碼

      先決條件

      步驟 1:設(shè)置項(xiàng)目結(jié)構(gòu)

      第 2 步:在 Python 中生成目錄樹圖

      編寫高級(jí) DirectoryTree 類

      編寫低級(jí) _TreeGenerator 類

      運(yùn)行目錄樹生成器代碼

      第 3 步:構(gòu)建目錄樹生成器的 CLI

      步驟 4:實(shí)施僅目錄選項(xiàng)

      步驟 5:將目錄樹圖保存到文件

      結(jié)論

      下一步

      使用用戶友好的命令行界面 (CLI)創(chuàng)建應(yīng)用程序是 Python 開發(fā)人員的一項(xiàng)有用技能。借助此技能,您可以創(chuàng)建工具來自動(dòng)化和加快工作環(huán)境中的任務(wù)。在本教程中,您將為命令行構(gòu)建一個(gè) Python 目錄樹生成器工具。

      該應(yīng)用程序?qū)⒃诿钚兄袑⒛夸浡窂阶鳛閰?shù),并在您的屏幕上顯示目錄樹圖。它還將提供其他選項(xiàng)來調(diào)整輸出。

      在本教程中,您將學(xué)習(xí)如何:

      使用 Python 的創(chuàng)建CLI 應(yīng)用程序argparse

      遞歸遍歷目錄結(jié)構(gòu)使用pathlib

      生成、格式化和顯示目錄樹圖

      將目錄樹圖保存到輸出文件

      您可以通過單擊下面的鏈接下載構(gòu)建此目錄樹生成器項(xiàng)目所需的代碼和其他資源:

      演示:Python 中的目錄樹生成器工具

      在本教程中,您將構(gòu)建一個(gè)命令行工具以在樹狀圖中列出目錄或文件夾的內(nèi)容。已經(jīng)有幾個(gè)成熟的解決方案可以執(zhí)行此任務(wù)。您會(huì)找到像command這樣的工具,它在大多數(shù)操作系統(tǒng)上都可用,以及其他工具,如treelib、dirtriex等。但是,找出您自己的解決方案來解決這個(gè)問題將是一個(gè)很好的學(xué)習(xí)練習(xí)。tree

      本教程將上述那種工具稱為目錄樹生成器。您將在此處構(gòu)建的工具將允許您生成并顯示一個(gè)樹狀圖,其中列出了文件系統(tǒng)中給定目錄的內(nèi)部結(jié)構(gòu)。在整個(gè)教程中,您還會(huì)發(fā)現(xiàn)這個(gè)圖被稱為目錄樹圖。

      您的目錄樹生成器將具有用戶友好的 CLI。它還將提供一些有趣的功能,例如在終端窗口上顯示帶有目錄內(nèi)容的樹形圖,并將該圖保存到外部文件中。

      這是本教程結(jié)束后應(yīng)用程序的外觀和工作方式:

      您的目錄樹生成器將提供一個(gè)功能齊全但最小的 CLI 和幾個(gè)選項(xiàng),允許您生成和顯示列出給定根目錄中所有文件和目錄的樹圖。

      項(xiàng)目概況

      您將在本教程中構(gòu)建的項(xiàng)目由一個(gè)命令行應(yīng)用程序組成,該應(yīng)用程序?qū)⒛夸浡窂阶鳛閰?shù),遍歷其內(nèi)部結(jié)構(gòu),并生成一個(gè)列出手頭目錄內(nèi)容的樹狀圖。在本節(jié)中,您將首先了解問題和可能的解決方案。您還將決定如何布置項(xiàng)目。

      布置項(xiàng)目

      要構(gòu)建您的目錄樹生成器,您將創(chuàng)建一些模塊和一個(gè)包。然后,您將為項(xiàng)目提供一個(gè)連貫的 Python應(yīng)用程序布局。在本教程結(jié)束時(shí),您項(xiàng)目的根目錄將具有以下目錄結(jié)構(gòu):

      ./rptree_project/ │ ├── rptree/ │ ├── rptree.py │ ├── __init__.py │ └── cli.py │ ├── README.md └── tree.py

      該rptree_project/目錄是項(xiàng)目的根目錄。在那里,您將放置以下文件:

      README.md提供有關(guān)安裝和運(yùn)行應(yīng)用程序的項(xiàng)目描述和說明。將描述性和詳細(xì)的README文件添加到您的項(xiàng)目被認(rèn)為是編程的最佳實(shí)踐,尤其是當(dāng)您計(jì)劃將項(xiàng)目作為開源解決方案發(fā)布時(shí)。

      tree.py?為您提供了一個(gè)入口點(diǎn)腳本來運(yùn)行應(yīng)用程序。

      然后你有rptree/一個(gè)包含三個(gè)模塊的 Python 包的目錄:

      rptree.py?提供應(yīng)用程序的主要功能。

      __init__.pyrptree/作為 Python 包啟用。

      cli.py?為應(yīng)用程序提供命令行界面。

      您的目錄樹生成器工具將在命令行上運(yùn)行。它將接受參數(shù),處理它們,并在終端窗口上顯示目錄樹圖。它還可以將輸出圖以降價(jià)格式保存到文件中。

      概述解決方案

      乍一看,遍歷文件系統(tǒng)中的目錄并生成反映其內(nèi)容的用戶友好的樹形圖可能不是一項(xiàng)艱巨的任務(wù)。但是,當(dāng)您開始考慮它時(shí),您會(huì)意識(shí)到它隱藏了很多復(fù)雜性。

      首先,這是一個(gè)涉及遞歸的問題。假設(shè)您在主目錄中打開了文件管理器,并且正在查找特定文件。然后雙擊Documents/子目錄并在屏幕上顯示其內(nèi)容。如果文件在那里,那么你打開它。否則,您打開另一個(gè)子目錄并繼續(xù)查找。您可以通過以下步驟描述此過程:

      打開一個(gè)目錄。

      檢查目錄內(nèi)容。

      如果找到該文件,請(qǐng)打開它。否則,返回第一步。

      結(jié)論是,處理目錄及其內(nèi)容是您通常使用recursion處理的一個(gè)問題。這就是您將在本教程中遵循的路徑。通常,您將運(yùn)行以下步驟:

      獲取文件系統(tǒng)上目錄的路徑。

      打開目錄。

      獲取其所有條目(目錄和文件)的列表。

      如果目錄包含子目錄,則從第二步開始重復(fù)該過程。

      要運(yùn)行第一步,您需要為應(yīng)用程序提供一種在命令行中獲取目錄路徑的方法。為此,您將使用標(biāo)準(zhǔn)庫中的Pythonargparse模塊。

      要完成第二步和第三步,您將使用pathlib.?該模塊提供了多種工具來管理和表示文件系統(tǒng)路徑。最后,您將使用常規(guī) Python列表來存儲(chǔ)目錄結(jié)構(gòu)中的條目列表。

      要考慮的第二點(diǎn)是如何塑造一個(gè)美觀的樹形圖,以準(zhǔn)確和用戶友好的方式反映目錄結(jié)構(gòu)。在本教程中,您將使用一種模仿tree命令功能的策略來塑造樹形圖,因此您的圖將與您在上一節(jié)中看到的一樣。

      組織代碼

      在設(shè)計(jì)方面,如果你想到手頭的問題并應(yīng)用單一職責(zé)原則,那么你可以根據(jù)三個(gè)主要職責(zé)來組織你的目錄樹生成器應(yīng)用程序的代碼:

      提供 CLI

      遍歷根目錄并構(gòu)建樹狀圖

      顯示樹狀圖

      與 CLI 相關(guān)的代碼將位于cli.py.?在 中rptree.py,您將放置與第二個(gè)和第三個(gè)職責(zé)相關(guān)的代碼。

      在本例中,您將編寫一個(gè)高級(jí)DirectoryTree類來生成和顯示樹形圖。您將在客戶端代碼或main 函數(shù)中使用此類。該類將提供一個(gè)調(diào)用方法.generate()來生成和顯示目錄樹圖。

      接下來,您將編寫一個(gè)低級(jí)_TreeGenerator類來遍歷目錄結(jié)構(gòu)并創(chuàng)建包含構(gòu)成樹狀圖的條目的列表。此類將提供一個(gè)調(diào)用方法.build_tree()來執(zhí)行此操作。

      樹狀圖將有兩個(gè)主要組成部分:

      Head將提供根目錄表示。

      正文將提供目錄內(nèi)容表示。

      樹頭表示將由根目錄的名稱和│連接樹頭和主體的附加管道 (?) 字符組成。

      樹體表示將由包含以下組件的字符串組成:

      提供所需間距以反映條目在目錄結(jié)構(gòu)中的位置的前綴字符串

      連接當(dāng)前子目錄或文件與其父目錄的字符

      當(dāng)前子目錄或文件的名稱

      以下是您將如何組合這些元素以構(gòu)建目錄樹圖的方法:

      您的樹生成器的.build_tree()方法將返回一個(gè)列表,其中包含構(gòu)成目錄樹圖的所有條目。要顯示圖表,您需要調(diào)用.generate()目錄樹對(duì)象。

      先決條件

      要完成本教程并充分利用它,您應(yīng)該熟悉以下概念:

      使用 Python 的argparse模塊創(chuàng)建命令行界面 (CLI)

      遍歷文件系統(tǒng)與pathlib

      在 Python 中使用遞歸和創(chuàng)建遞歸函數(shù)

      處理文件usingopen()和with語句

      使用print()打印文本到屏幕上,也寫入物理文件在你的文件系統(tǒng)

      在 Python 中使用面向?qū)ο缶幊?/p>

      如果您在開始本教程之前沒有掌握所有必需的知識(shí),那也沒關(guān)系!您可以隨時(shí)停下來查看以下資源:

      如何使用 argparse 在 Python 中構(gòu)建命令行接口

      Python 3 的 pathlib 模塊:馴服文件系統(tǒng)

      在 Python 中遞歸思考

      在 Python 中處理文件

      Python print() 函數(shù)指南

      Python 3 中的面向?qū)ο缶幊?(OOP)

      在軟件依賴方面,您的目錄樹生成器項(xiàng)目不需要任何外部庫。它的所有依賴項(xiàng)都可以作為 Python 內(nèi)置函數(shù)或作為標(biāo)準(zhǔn)庫中的模塊使用。

      也就是說,是時(shí)候用真實(shí)的代碼弄臟你的手并構(gòu)建你自己的目錄樹生成器工具了!

      步驟 1:設(shè)置項(xiàng)目結(jié)構(gòu)

      首先,您需要為目錄樹生成器項(xiàng)目創(chuàng)建一致的應(yīng)用程序布局。繼續(xù)在您的文件系統(tǒng)上創(chuàng)建一個(gè)名為 的新目錄rptree_project/。在此目錄中,您需要兩個(gè)空文件:

      README.md

      tree.py

      接下來,你需要?jiǎng)?chuàng)建一個(gè)名為的子目錄rptree/,在它下面的空文件:rptree.py,__init__.py,和-?cli.py。添加后,您的項(xiàng)目的根目錄應(yīng)如下所示:

      ./rptree_project/ │ ├── rptree/ │ ├── rptree.py │ ├── __init__.py │ └── cli.py │ ├── README.md └── tree.py

      要下載這些文件以及您將在本節(jié)中添加到其中的代碼,請(qǐng)單擊以下鏈接:

      此時(shí),您需要一個(gè)額外的設(shè)置步驟。在項(xiàng)目目錄中啟動(dòng)您最喜歡的代碼編輯器或 IDE,打開__init__.py并添加以下內(nèi)容:

      # __init__.py """Top-level package for RP Tree.""" __version__ = "0.1.0"

      Python 使用__init__.py文件將普通目錄轉(zhuǎn)換為包。包包含的模塊,如rptree.py和cli.py此項(xiàng)目。包和模塊是允許您組織和構(gòu)建 Python 代碼的機(jī)制。

      在這種情況下,__init__.py包含模塊的文檔字符串,通常稱為docstring。它還定義了一個(gè)名為的全局常量__version__,用于保存應(yīng)用程序的版本號(hào)。

      最后,您需要一個(gè)示例目錄來測試應(yīng)用程序并確保它正常工作。保留項(xiàng)目的根目錄并在文件系統(tǒng)中創(chuàng)建以下目錄結(jié)構(gòu),并與項(xiàng)目文件夾并排:

      ../hello/ │ ├── hello/ │ ├── __init__.py │ └── hello.py │ ├── tests/ │ └── test_hello.py │ ├── requirements.txt ├── setup.py ├── README.md └── LICENSE

      此目錄結(jié)構(gòu)模仿 Python 項(xiàng)目的總體布局。在本教程的整個(gè)步驟中,您將使用此示例目錄結(jié)構(gòu)來測試目錄樹生成器工具。這樣,您可以在教程的任何給定步驟中將結(jié)果與預(yù)期結(jié)果進(jìn)行比較。

      第 2 步:在 Python 中生成目錄樹圖

      既然您已經(jīng)了解了項(xiàng)目的要求,并且已經(jīng)設(shè)置了項(xiàng)目布局和示例目錄,您就可以開始處理真正的代碼了。因此,讓您的編輯器準(zhǔn)備好開始編碼。

      現(xiàn)在回到您的代碼編輯器并打開rptree.py.?然后將以下代碼添加到文件中:

      # rptree.py """This module provides RP Tree main module.""" import os import pathlib PIPE = "│" ELBOW = "└──" TEE = "├──" PIPE_PREFIX = "│ " SPACE_PREFIX = " "

      在這段代碼中,您首先從 Python 標(biāo)準(zhǔn)庫導(dǎo)入?os和pathlib。接下來,您定義幾個(gè)模塊級(jí)常量來保存連接器字符和前綴字符串,您將使用它們?cè)诮K端窗口上繪制樹形圖。您將用于繪制樹狀圖的符號(hào)與您在本教程之前的圖中看到的符號(hào)相同。命令行工具tree使用這些相同的符號(hào)來繪制樹形圖。

      編寫高級(jí)DirectoryTree類

      接下來,您將定義一個(gè)高級(jí)類來創(chuàng)建目錄樹圖并將其顯示在屏幕上。為類命名DirectoryTree并向其添加以下代碼:

      # rptree.py # Snip... class DirectoryTree: def __init__(self, root_dir): self._generator = _TreeGenerator(root_dir) def generate(self): tree = self._generator.build_tree() for entry in tree: print(entry)

      在類初始化,你拿根目錄作為參數(shù),并創(chuàng)建一個(gè)實(shí)例屬性叫._generator。要?jiǎng)?chuàng)建此屬性,您可以使用稱為組合的 OOP 技術(shù),該技術(shù)定義了“具有”關(guān)系。這意味著每個(gè)DirectoryTree對(duì)象都有一個(gè)?_TreeGenerator附加的對(duì)象。

      注意:名稱中的前導(dǎo)下劃線字符 (?_)_TreeGenerator是常用的 Python 約定。這意味著該類是nonpublic,這意味著您不希望從其包含的模塊 之外使用該類rptree.py。

      同樣的約定適用于非公共方法和屬性,您不希望在包含類的外部使用它們。通常,您開始將屬性定義為非公共屬性,并在需要時(shí)將它們?cè)O(shè)為公共屬性。有關(guān)此約定的更多詳細(xì)信息,請(qǐng)參閱PEP 8。

      您將_TreeGenerator在一分鐘內(nèi)看到如何創(chuàng)建這個(gè)類。現(xiàn)在,看看.generate()。此方法創(chuàng)建一個(gè)名為的局部變量tree,該變量保存調(diào)用.build_tree()樹生成器對(duì)象的結(jié)果。然后使用for循環(huán)entry將樹中的每個(gè)打印到屏幕上。

      編碼低級(jí)_TreeGenerator類

      現(xiàn)在您已經(jīng)完成了編碼DirectoryTree,是時(shí)候編寫遍歷文件系統(tǒng)并生成目錄樹圖的類了:

      1# rptree.py 2# Snip... 3 4class _TreeGenerator: 5 def __init__(self, root_dir): 6 self._root_dir = pathlib.Path(root_dir) 7 self._tree = [] 8 9 def build_tree(self): 10 self._tree_head() 11 self._tree_body(self._root_dir) 12 return self._tree 13 14 def _tree_head(self): 15 self._tree.append(f"{self._root_dir}{os.sep}") 16 self._tree.append(PIPE)

      下面是這段代碼的工作原理:

      第 4 行定義了一個(gè)新類_TreeGenerator。

      第 5 行定義了類初始值設(shè)定項(xiàng)。在這種情況下,.__init__()將root_dir作為參數(shù)。它保存樹的根目錄路徑。請(qǐng)注意,您將root_dir變成一個(gè)pathlib.Path對(duì)象并將其分配給非公共實(shí)例屬性._root_dir。

      第 7 行定義了一個(gè)空列表來存儲(chǔ)構(gòu)成目錄樹圖的條目。

      第 9 到 12 行定義了.build_tree().?此公共方法生成并返回目錄樹圖。在內(nèi)部.build_tree(),您首先調(diào)用._tree_head()構(gòu)建樹頭。然后你調(diào)用._tree_body()with._root_dir作為參數(shù)來生成圖表的其余部分。

      第 14 到 16 行定義了._tree_head().?此方法將根目錄的名稱添加到._tree.?然后添加一個(gè)PIPE將根目錄連接到樹的其余部分。

      到目前為止,您只編寫了類的第一部分。下一步是編寫._tree_body(),這將需要幾行代碼。

      注意:上述代碼和本教程中其余代碼示例中的行號(hào)旨在方便解釋。它們與最終模塊或腳本中的行順序不匹配。

      中的代碼._tree_body()提供了類的低級(jí)功能。它以一個(gè)目錄路徑為參數(shù),遍歷該目錄下的文件系統(tǒng),生成相應(yīng)的目錄樹圖。這是它的實(shí)現(xiàn):

      為命令行構(gòu)建 Python 目錄樹生成器(命令行創(chuàng)建)

      1# rptree.py 2# Snip... 3 4class _TreeGenerator: 5 # Snip... 6 7 def _tree_body(self, directory, prefix=""): 8 entries = directory.iterdir() 9 entries = sorted(entries, key=lambda entry: entry.is_file()) 10 entries_count = len(entries) 11 for index, entry in enumerate(entries): 12 connector = ELBOW if index == entries_count - 1 else TEE 13 if entry.is_dir(): 14 self._add_directory( 15 entry, index, entries_count, prefix, connector 16 ) 17 else: 18 self._add_file(entry, prefix, connector)

      這段代碼發(fā)生了很多事情。這是它的作用,一行一行:

      第 7 行定義了._tree_body().?這個(gè)方法有兩個(gè)參數(shù):

      directory保存要遍歷的目錄的路徑。注意directory應(yīng)該是一個(gè)pathlib.Path對(duì)象。

      prefix保存用于在終端窗口上繪制樹形圖的前綴字符串。此字符串有助于顯示目錄或文件在文件系統(tǒng)中的位置。

      8部線電話.iterdir()上directory,然后將結(jié)果來entries。此調(diào)用.iterdir()返回包含在directory.

      第 9 行對(duì)directoryusing 中的條目進(jìn)行排序sorted()。為此,您需要?jiǎng)?chuàng)建一個(gè)lambda函數(shù)來檢查是否entry為文件并相應(yīng)地返回True或返回False。在 Python 中,True和False在內(nèi)部分別表示為整數(shù)、1和0。最終效果是sorted()將目錄放在最前面,因?yàn)閑ntry.is_file() == False == 0將文件放在后面,因?yàn)閑ntry.is_file() == True == 1.

      第 10 行調(diào)用len()以獲取directory手頭的條目數(shù)。

      第 11 行開始一個(gè)for循環(huán),它對(duì) 中的條目進(jìn)行迭代directory。該循環(huán)用于enumerate()將索引與每個(gè)條目相關(guān)聯(lián)。

      第 12 行定義了您將用于在終端窗口上繪制樹狀圖的連接器符號(hào)。例如,如果當(dāng)前條目是目錄 (?index == entries_count - 1) 中的最后一個(gè)條目,那么您可以使用彎頭 (?└──) 作為connector.?否則,您將使用 T 恤 (?├──)。

      第 13 到 18 行定義了一個(gè)條件語句,用于檢查當(dāng)前條目是否為目錄。如果是,則if代碼塊調(diào)用._add_directory()以添加新目錄條目。否則,該else子句調(diào)用._add_file()以添加新文件條目。

      要完成編碼_TreeGenerator,您需要編寫._add_directory()和._add_file()。這是這些非公共方法的代碼:

      1# rptree.py 2# Snip... 3 4class _TreeGenerator: 5 # Snip... 6 7 def _add_directory( 8 self, directory, index, entries_count, prefix, connector 9 ): 10 self._tree.append(f"{prefix}{connector} {directory.name}{os.sep}") 11 if index != entries_count - 1: 12 prefix += PIPE_PREFIX 13 else: 14 prefix += SPACE_PREFIX 15 self._tree_body( 16 directory=directory, 17 prefix=prefix, 18 ) 19 self._tree.append(prefix.rstrip()) 20 21 def _add_file(self, file, prefix, connector): 22 self._tree.append(f"{prefix}{connector} {file.name}")

      下面是這段代碼的作用,一行一行:

      第 7 行定義了._add_directory().?這是一個(gè)輔助方法,它接受五個(gè)參數(shù),不計(jì)算self。您已經(jīng)知道每個(gè)參數(shù)代表什么,因此無需再次介紹它們。

      第 10行將一個(gè)新目錄附加到._tree.?中的每個(gè)目錄._tree都由包含 a?prefix、 a?connector、目錄名稱 (?entry.name) 和最終分隔符 (?os.sep)的字符串表示。請(qǐng)注意,分隔符是平臺(tái)相關(guān)的,這意味著您的樹生成器使用與您當(dāng)前的操作系統(tǒng)相對(duì)應(yīng)的分隔符。

      第 11 到 14 行運(yùn)行一個(gè)條件語句,該語句prefix根據(jù)index當(dāng)前條目的更新。

      第 15 到 18 行調(diào)用._tree_body()了一組新參數(shù)。

      第 19 行追加了一個(gè) newprefix來將當(dāng)前目錄的內(nèi)容與下一個(gè)目錄的內(nèi)容分開。

      ._tree_body()在第 15 行的調(diào)用中有一個(gè)重要的細(xì)節(jié)討論。這是一個(gè)間接遞歸調(diào)用。換句話說,._tree_body()就是通過._add_directory()直到遍歷整個(gè)目錄結(jié)構(gòu)來調(diào)用自己。

      最后,在第 21 和 22 行,您定義._add_file().?此方法將文件條目附加到目錄樹列表中。

      運(yùn)行目錄樹生成器代碼

      哇!那是很多工作!您的目錄樹生成器現(xiàn)在提供其主要功能。是時(shí)候試一試了。在項(xiàng)目的根目錄上打開一個(gè)Python 交互式會(huì)話并鍵入以下代碼:

      >>>

      >>> from rptree.rptree import DirectoryTree >>> tree = DirectoryTree("../hello") >>> tree.generate() ../hello/ │ ├── hello/ │ ├── __init__.py │ └── hello.py │ ├── tests/ │ └── test_hello.py │ ├── requirements.txt ├── setup.py ├── README.md └── LICENSE

      在這里,您首先DirectoryTree從rptree.py.?接下來,您創(chuàng)建一個(gè)目錄樹對(duì)象,將路徑傳遞到之前創(chuàng)建的hello/示例目錄。當(dāng)您調(diào)用.generate()目錄樹對(duì)象時(shí),您會(huì)在屏幕上打印完整的目錄樹圖。

      涼爽的!您已經(jīng)編寫了目錄樹生成器的主要功能。在下一部分中,您將為您的項(xiàng)目提供一個(gè)漂亮且用戶友好的命令行界面和一個(gè)可執(zhí)行腳本。

      第 3 步:構(gòu)建目錄樹生成器的 CLI

      有多種工具可用于創(chuàng)建 CLI 應(yīng)用程序。一些比較流行的有Click、docopt、Typer以及argparse標(biāo)準(zhǔn)庫中的 。在您的目錄樹生成器項(xiàng)目中,您將使用argparse提供命令行界面。這樣,您將避免外部依賴。

      Pythonargparse允許您定義應(yīng)用程序?qū)⒃诿钚兄胁捎玫膮?shù)并驗(yàn)證用戶的輸入。該模塊還為您的腳本生成幫助和使用消息。

      要下載您將在此部分添加或修改的文件和代碼,請(qǐng)單擊以下鏈接:

      要實(shí)現(xiàn)目錄樹生成器的 CLI,請(qǐng)返回項(xiàng)目目錄并cli.py從rptree包中打開文件。然后輸入以下代碼:

      """This module provides the RP Tree CLI.""" # cli.py import argparse import pathlib import sys from . import __version__ from .rptree import DirectoryTree def main(): args = parse_cmd_line_arguments() root_dir = pathlib.Path(args.root_dir) if not root_dir.is_dir(): print("The specified root directory doesn't exist") sys.exit() tree = DirectoryTree(root_dir) tree.generate()

      在這段代碼中,您首先從標(biāo)準(zhǔn)庫中導(dǎo)入所需的模塊。然后您導(dǎo)入__version__并且也DirectoryTree從包含的包中導(dǎo)入rptree.

      在 中main(),您首先在 中調(diào)用parse_cmd_line_arguments()并打包命令行參數(shù)args。您將在一分鐘內(nèi)看到此函數(shù)的作用。接下來,將根目錄轉(zhuǎn)換為pathlib.Path對(duì)象。條件語句進(jìn)行快速驗(yàn)證以確保用戶提供有效的目錄路徑,否則退出應(yīng)用程序。

      最后,您創(chuàng)建一個(gè)用作參數(shù)的DirectoryTree對(duì)象root_dir并調(diào)用.generate()它以在終端窗口上生成和顯示相應(yīng)的目錄樹圖。

      現(xiàn)在您可以深入了解parse_cmd_line_arguments().?此函數(shù)提供所有與 CLI 相關(guān)的功能:

      1# cli.py 2# Snip... 3 4def parse_cmd_line_arguments(): 5 parser = argparse.ArgumentParser( 6 prog="tree", 7 description="RP Tree, a directory tree generator", 8 epilog="Thanks for using RP Tree!", 9 ) 10 parser.version = f"RP Tree v{__version__}" 11 parser.add_argument("-v", "--version", action="version") 12 parser.add_argument( 13 "root_dir", 14 metavar="ROOT_DIR", 15 nargs="?", 16 default=".", 17 help="Generate a full directory tree starting at ROOT_DIR", 18 ) 19 return parser.parse_args()

      下面是這個(gè)函數(shù)的作用:

      第 5 行實(shí)例化argparse.ArgumentParser,提供應(yīng)用程序的命令名稱 (?prog)、description程序的簡短內(nèi)容以及epilog在用戶運(yùn)行應(yīng)用程序的幫助選項(xiàng)后顯示的短語。這個(gè)類為用戶在命令行輸入的所有參數(shù)提供了一個(gè)解析器。

      第 10行將解析器的version屬性設(shè)置為包含應(yīng)用程序名稱及其當(dāng)前版本的字符串__version__。

      第 11行將第一個(gè)可選參數(shù)添加到應(yīng)用程序的 CLI。該-v或--version標(biāo)志被要求提供這種說法,里面有你的終端窗口上顯示應(yīng)用程序的版本字符串的默認(rèn)操作。

      第 12 到 18 行向CLI 添加了第二個(gè)參數(shù)。這里,root_dir是一個(gè)位置參數(shù),它包含您將用作生成目錄樹圖的起點(diǎn)的目錄路徑。在這種情況下,有四個(gè)參數(shù).add_argument():

      metavar?在用法消息中保存參數(shù)的名稱。

      nargs定義您的程序在手頭的參數(shù)下可以采用的值的數(shù)量。例如,你的目錄樹生成器只能取一個(gè)在命令行目錄路徑,所以適當(dāng)?shù)闹祅args是"?"。

      default為手頭的參數(shù)提供默認(rèn)值。在這種情況下,您使用點(diǎn) (?".") 將當(dāng)前目錄設(shè)置為默認(rèn)根目錄。

      help?提供描述參數(shù)作用的簡短幫助消息。

      第 19 行使用 解析提供的參數(shù).parse_args()。此方法返回一個(gè)Namespace包含所有提供的參數(shù)的對(duì)象。您可以使用命名空間對(duì)象上的點(diǎn)表示法訪問這些參數(shù)。請(qǐng)注意,您在args編寫main().

      完成這一步旅程的最后一步是提供一個(gè)入口點(diǎn)腳本。回到您的代碼編輯器并打開tree.py,然后向其中添加以下代碼:

      #!/usr/bin/env python3 # tree.py """This module provides RP Tree entry point script.""" from rptree.cli import main if __name__ == "__main__": main()

      該文件簡短明了。您首先導(dǎo)入main()fromcli.py然后將其調(diào)用包裝在傳統(tǒng)if __name__ == "__main__":條件中,以便 Pythonmain()僅在您將文件作為程序運(yùn)行而不是將其作為模塊導(dǎo)入時(shí)才調(diào)用。

      有了這個(gè)腳本,您就可以開始使用全新的命令行目錄樹生成器了。打開命令行窗口,移至項(xiàng)目目錄,然后運(yùn)行以下命令:

      $ python tree.py ../hello ../hello/ │ ├── hello/ │ ├── __init__.py │ └── hello.py │ ├── tests/ │ └── test_hello.py │ ├── requirements.txt ├── setup.py ├── README.md └── LICENSE $ python tree.py -v RP Tree v0.1.0 $ python tree.py --help usage: tree [-h] [-v] [ROOT_DIR] RP Tree, a directory tree generator positional arguments: ROOT_DIR Generate a full directory tree starting at ROOT_DIR optional arguments: -h, --help show this help message and exit -v, --version show program's version number and exit Thanks for using RP Tree!

      就是這樣!您的目錄樹生成器工具有效。它生成并在屏幕上顯示用戶友好的樹形圖。它還提供版本和使用信息。這對(duì)于大約一百行代碼來說非常酷!在接下來的部分中,您將向應(yīng)用程序添加更多功能。

      步驟 4:實(shí)施僅目錄選項(xiàng)

      添加到目錄樹生成器的一個(gè)有趣功能是能夠生成和顯示僅目錄樹圖。換句話說,一個(gè)只顯示目錄的圖表。在此項(xiàng)目中,您將添加-d和--dir-only標(biāo)記來完成此操作,但在此之前,您需要進(jìn)行更新_TreeGenerator以支持此新功能。

      您可以通過單擊以下鏈接下載將在此部分中添加或修改的文件和代碼:

      獲取示例代碼:?單擊此處獲取示例代碼,您將在本教程中使用 Python 構(gòu)建目錄樹生成器。

      現(xiàn)在打開rptree.py模塊并像這樣更新它的代碼:

      # rptree.py # Snip... class _TreeGenerator: def __init__(self, root_dir, dir_only=False): self._root_dir = pathlib.Path(root_dir) self._dir_only = dir_only self._tree = [] # Snip... def _tree_body(self, directory, prefix=""): entries = self._prepare_entries(directory) entries_count = len(entries) for index, entry in enumerate(entries): connector = ELBOW if index == entries_count - 1 else TEE if entry.is_dir(): self._add_directory( entry, index, entries_count, prefix, connector ) else: self._add_file(entry, prefix, connector) def _prepare_entries(self, directory): entries = directory.iterdir() if self._dir_only: entries = [entry for entry in entries if entry.is_dir()] return entries entries = sorted(entries, key=lambda entry: entry.is_file()) return entries # Snip...

      首先,您將dir_only作為參數(shù)添加到類初始值設(shè)定項(xiàng)中。這是一個(gè)布爾參數(shù),允許您根據(jù)用戶在命令行的輸入生成完整的樹或僅目錄樹。此參數(shù)默認(rèn)為False因?yàn)樯赏暾麡涫亲畛R姷挠美?/p>

      在第二個(gè)突出顯示的行中,您創(chuàng)建一個(gè)實(shí)例屬性,調(diào)用它._dir_only來保存新添加的參數(shù)。

      在突出顯示的第三行中,您將兩行原始代碼替換為對(duì) 的調(diào)用._prepare_entries()。顧名思義,此函數(shù)準(zhǔn)備目錄條目以生成完整樹或僅目錄樹。

      在._prepare_entries(),你首先得到entries?發(fā)電機(jī)。該if語句檢查是否._dir_only為True。如果是這樣,那么您使用列表理解過濾掉文件并返回list目錄。如果._dir_only是False,那么您對(duì)條目進(jìn)行排序,重復(fù)使用您之前看到的相同代碼。最后,您返回 中條目的完整列表directory。

      現(xiàn)在您需要確保將這個(gè)新參數(shù)傳遞給_TreeGeneratorback in的實(shí)例DirectoryTree:

      # rptree.py # Snip... class DirectoryTree: def __init__(self, root_dir, dir_only=False): self._generator = _TreeGenerator(root_dir, dir_only) # Snip...

      在突出顯示的第一行中,您添加一個(gè)新參數(shù)dir_only,該參數(shù)稱為類初始值設(shè)定項(xiàng)。在突出顯示的第二行中,確保將新參數(shù)傳遞給 的構(gòu)造函數(shù)_TreeGenerator。

      完成這些更改后,您可以更新cli.py文件,以便應(yīng)用程序可以在命令行中獲取和處理-d和--dir-only標(biāo)志。首先,您需要更新main():

      # cli.py # Snip... def main(): # Snip... tree = DirectoryTree(root_dir, dir_only=args.dir_only) tree.generate()

      在突出顯示的行中,您傳遞args.dir_only給 的dir_only參數(shù)DirectoryTree。args命名空間的這個(gè)屬性包含一個(gè)取決于用戶輸入的布爾值。如果用戶在命令行提供-dor--dir-only選項(xiàng),則args.dir_only是True。否則,它是False。

      接下來,將這些-d和--dir-only標(biāo)志添加到命令行界面。為此,您需要parse_cmd_line_arguments()像這樣更新:

      # cli.py # Snip... def parse_cmd_line_arguments(): # Snip... parser.add_argument( "-d", "--dir-only", action="store_true", help="Generate a directory-only tree", ) return parser.parse_args()

      action調(diào)用中的參數(shù).add_argument()保存 value?"store_true",這意味著該參數(shù)自動(dòng)存儲(chǔ)True或False根據(jù)用戶的輸入。在這種情況下,如果用戶在命令行提供-dor--dir-only標(biāo)志,則參數(shù)存儲(chǔ)True.?否則,它存儲(chǔ)False.

      有了這個(gè)更新,就可以運(yùn)行和測試應(yīng)用程序了。返回終端窗口并執(zhí)行以下命令:

      $ python tree.py ../hello -d ../hello/ │ ├── hello/ │ └── tests/

      從現(xiàn)在開始,如果您在命令行中提供-d或-dir-only標(biāo)志,則樹形圖僅顯示示例hello/目錄中的子目錄。

      步驟 5:將目錄樹圖保存到文件

      在本節(jié)中,您將向目錄樹生成器工具添加最終功能。您將為應(yīng)用程序提供將生成的目錄樹圖保存到外部文件的功能。為此,您將使用標(biāo)志-o和--output-file.

      像往常一樣,要下載您將在此部分添加或修改的代碼,請(qǐng)單擊以下鏈接:

      現(xiàn)在返回rptree.py并更新DirectoryTree如下:

      # rptree.py # Snip... import sys # Snip... class DirectoryTree: def __init__(self, root_dir, dir_only=False, output_file=sys.stdout): self._output_file = output_file self._generator = _TreeGenerator(root_dir, dir_only) def generate(self): tree = self._generator.build_tree() if self._output_file != sys.stdout: # Wrap the tree in a markdown code block tree.insert(0, "```") tree.append("```") self._output_file = open( self._output_file, mode="w", encoding="UTF-8" ) with self._output_file as stream: for entry in tree: print(entry, file=stream)

      此更新幾乎是對(duì)DirectoryTree.?首先,您向名為 的類初始值設(shè)定項(xiàng)添加一個(gè)新參數(shù)output_file。此參數(shù)默認(rèn)為sys.stdout,這是標(biāo)準(zhǔn)輸出(您的屏幕)。然后將新添加的參數(shù)存儲(chǔ)在名為 的實(shí)例屬性中._output_file。

      在 中.generate(),您首先構(gòu)建目錄樹圖并將其存儲(chǔ)在tree.?條件語句檢查用戶是否提供了不同于sys.stdout.?如果是,則if代碼塊使用反引號(hào) (?"```")將樹形圖包裝在降價(jià)代碼塊中。

      接下來,您使用打開提供的輸出文件,open()以便您可以使用with語句處理它。

      注意:.insert(0, x)就執(zhí)行時(shí)間而言,調(diào)用列表對(duì)象可能是一項(xiàng)代價(jià)高昂的操作。這是因?yàn)?Python 需要將所有項(xiàng)目向右移動(dòng)一個(gè)位置,然后在第一個(gè)位置插入新項(xiàng)目。

      一種有效的替代方法.insert()是collections.deque使用.appendleft().?此數(shù)據(jù)結(jié)構(gòu)針對(duì)此類操作進(jìn)行了優(yōu)化。

      在with塊中,您開始for循環(huán)以將目錄樹圖打印到提供的輸出文件。請(qǐng)注意,print()也可以寫入文件系統(tǒng)上的常規(guī)文件。為此,您只需要提供一個(gè)自定義file參數(shù)。要深入了解 的功能print(),請(qǐng)查看Python print() 函數(shù)指南。

      完成后DirectoryTree,您可以更新命令行界面以啟用輸出文件選項(xiàng)。返回cli.py并像這樣修改它:

      # cli.py # Snip... def main(): # Snip... tree = DirectoryTree( root_dir, dir_only=args.dir_only, output_file=args.output_file ) tree.generate() def parse_cmd_line_arguments(): # Snip... parser.add_argument( "-o", "--output-file", metavar="OUTPUT_FILE", nargs="?", default=sys.stdout, help="Generate a full directory tree and save it to a file", ) return parser.parse_args()

      第一步是將輸出文件作為DirectoryTree構(gòu)造函數(shù)中的參數(shù)。輸出文件(如果有)將存儲(chǔ)在args.output_file.

      接下來,您將一個(gè)新參數(shù)添加到parser.?這個(gè)參數(shù)有兩個(gè)標(biāo)志:-o和--output-file。要提供替代輸出文件,用戶必須使用這些標(biāo)志之一并在命令行中提供文件的路徑。請(qǐng)注意,輸出文件默認(rèn)為sys.stdout.?這樣,如果用戶不提供輸出文件,則應(yīng)用程序會(huì)自動(dòng)使用標(biāo)準(zhǔn)輸出屏幕。

      您可以通過在終端上運(yùn)行以下命令來測試新添加的選項(xiàng):

      $ python tree.py ../hello -o output_file.md

      此命令生成一個(gè)完整的目錄樹圖并將其保存到output_file.md當(dāng)前目錄中的文件中。如果您打開該文件,那么您將看到以降價(jià)格式保存在那里的目錄樹圖。

      就是這樣!您的目錄樹生成器項(xiàng)目已完成。除了生成和顯示完整目錄樹圖的默認(rèn)選項(xiàng)外,該應(yīng)用程序還提供以下選項(xiàng):

      -v,--version顯示當(dāng)前版本信息并退出應(yīng)用程序。

      -h,--help顯示幫助和使用信息。

      -d,--dir-only生成僅目錄樹并將其打印到屏幕上。

      -o,--output-to-markdown生成一棵樹,并以markdown格式保存到文件中。

      您現(xiàn)在擁有一個(gè)功能齊全的命令行工具,可以生成用戶友好的目錄樹圖。很好!

      結(jié)論

      您可以通過創(chuàng)建CLI工具和應(yīng)用程序來自動(dòng)化和加速工作環(huán)境中的多個(gè)流程和任務(wù)。在 Python 中,您可以使用argparse或其他第三方庫快速創(chuàng)建此類工具。在本教程中,您編寫了一個(gè)完整的項(xiàng)目來為命令行構(gòu)建 Python目錄樹生成器工具。

      該應(yīng)用程序在命令行中獲取目錄路徑,生成目錄樹圖,并將其顯示在終端窗口中或?qū)⑵浔4娴轿募到y(tǒng)上的外部文件中。它還提供了更多選項(xiàng)來調(diào)整生成的樹圖。

      在本教程中,您學(xué)習(xí)了如何:

      使用 Python 的創(chuàng)建CLI 應(yīng)用程序argparse

      遞歸遍歷目錄結(jié)構(gòu)使用pathlib

      生成、格式化和打印目錄樹圖

      將目錄樹圖保存到輸出文件

      目錄樹生成器項(xiàng)目的最終源代碼可供您下載。要獲取它,請(qǐng)單擊以下鏈接:

      下一步

      到目前為止,您已經(jīng)構(gòu)建了一個(gè)功能齊全的目錄樹生成器工具。盡管該應(yīng)用程序提供了最少的功能集,但它是您繼續(xù)添加功能并在此過程中學(xué)習(xí)的良好起點(diǎn)。這將幫助您將 Python 和 CLI 應(yīng)用程序的技能提升到一個(gè)新的水平。

      以下是您可以實(shí)施以繼續(xù)改進(jìn)目錄樹生成器工具的一些想法:

      添加對(duì)文件和目錄排序的支持:對(duì)文件和目錄進(jìn)行排序的能力是一項(xiàng)很棒的功能。例如,您可以添加-s和--sort-tree布爾標(biāo)志,以允許用戶調(diào)整在最后的樹形圖的文件和目錄的順序。

      向樹狀圖添 加圖標(biāo)和顏色:添加圖標(biāo)、字體顏色或兩者都是實(shí)現(xiàn)的一個(gè)很好的功能。例如,您可以為目錄使用自定義文件夾圖標(biāo),為文件使用基于文件類型的圖標(biāo)。

      設(shè)置應(yīng)用程序以將其作為開源項(xiàng)目發(fā)布:準(zhǔn)備將應(yīng)用程序作為開源項(xiàng)目發(fā)布到 PyPI 可能是一個(gè)有趣的挑戰(zhàn)。這樣做可以讓您與朋友和同事分享您的工作。要開始將包發(fā)布到 PyPI,請(qǐng)查看如何將開源 Python 包發(fā)布到 PyPI。

      Python

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:【網(wǎng)絡(luò)通訊與網(wǎng)絡(luò)安全】網(wǎng)絡(luò)通訊中的隨機(jī)數(shù)如果不隨機(jī)會(huì)怎么樣?(上)
      下一篇:多屏幕適配相關(guān)(多屏協(xié)同適配機(jī)型)
      相關(guān)文章
      亚洲中久无码永久在线观看同| 亚洲AV无码一区二区三区性色 | 亚洲乱码中文字幕综合| 国产亚洲漂亮白嫩美女在线| 亚洲日韩亚洲另类激情文学| 亚洲另类古典武侠| 亚洲日韩中文字幕天堂不卡| 亚洲高清美女一区二区三区| 亚洲美女大bbbbbbbbb| 亚洲国产综合在线| 亚洲国产精品成人久久久| 亚洲精品偷拍无码不卡av| 亚洲福利一区二区| 亚洲大尺码专区影院| 亚洲视频在线观看视频| 亚洲无限乱码一二三四区| 亚洲成a人片7777| 亚洲一卡2卡4卡5卡6卡在线99 | 亚洲国产日韩在线观频| 亚洲Av无码国产情品久久| 亚洲伊人久久大香线蕉综合图片| 亚洲国产成人五月综合网| 亚洲最大的成网4438| 中文字幕亚洲色图| 亚洲国产精品无码久久久| tom影院亚洲国产一区二区| 亚洲蜜芽在线精品一区| 亚洲冬月枫中文字幕在线看| 亚洲区视频在线观看| 亚洲视频无码高清在线| 亚洲精品无码久久久久A片苍井空 亚洲精品无码久久久久YW | 亚洲av高清在线观看一区二区| 亚洲成a人片在线观看日本麻豆| 在线a亚洲v天堂网2018| MM131亚洲国产美女久久| 国产亚洲精久久久久久无码77777| 亚洲精品国产成人片| 亚洲成AV人片在线观看无| 亚洲美日韩Av中文字幕无码久久久妻妇| 亚洲欧洲精品成人久久奇米网 | 亚洲欧美日本韩国|