99热99这里只有精品6国产,亚洲中文字幕在线天天更新,在线观看亚洲精品国产福利片 ,久久久久综合网

歡迎加入QQ討論群258996829
麥子學(xué)院 頭像
蘋果6袋
6
麥子學(xué)院

Python文檔編輯器編寫方法步驟詳解

發(fā)布時(shí)間:2016-12-09 20:00  回復(fù):0  查看:3172   最后回復(fù):2016-12-09 20:00  

在我剛開始接觸Python語言的日子里,我最喜歡做的事情之一是坐在解釋器旁使用內(nèi)置help功能來檢查類和方法,決定下一個(gè)要敲的內(nèi)容。這個(gè)功能導(dǎo)入一個(gè)對象,遍布它的成員,取出文檔注釋,生成一個(gè)類似manpage的輸出,從而幫助你找到如何使用正在檢查的對象的方法。

  它被內(nèi)置成一個(gè)標(biāo)準(zhǔn)庫的美妙之處在于通過代碼直接生成輸出,它為我這樣的懶人間接地強(qiáng)調(diào)了一個(gè)編碼風(fēng)格,我就想著在盡量少做額外的工作的情況下維護(hù)文檔。尤其是如果你已經(jīng)為你的變量和函數(shù)選擇直接的名字。 這種風(fēng)格涉及到向你的函數(shù)和類添加文檔字符串,以及通過用下劃線前綴來正確地識別私有成員和受保護(hù)成員。

  Help on class list in module builtins:

  class list(object)

  | list() -> new empty list

  | list(iterable) -> new list initialized from iterable's items

  |

  | Methods defined here:

  |

  | __add__(self, value, /)

  | Return self+value.

  ...

  | __iter__(self, /)

  | Implement iter(self).

  ...

  | append(...)

  | L.append(object) -> None -- append object to end

  |

  | extend(...)

  | L.extend(iterable) -> None -- extend list by appending elements from the iterable

  |

  | index(...)

  | L.index(value, [start, [stop]]) -> integer -- return first index of value.

  | Raises ValueError if the value is not present.

  ...

  | pop(...)

  | L.pop([index]) -> item -- remove and return item at index (default last).

  | Raises IndexError if list is empty or index is out of range.

  |

  | remove(...)

  | L.remove(value) -> None -- remove first occurrence of value.

  | Raises ValueError if the value is not present.

  ...

  | ----------------------------------------------------------------------

  | Data and other attributes defined here:

  |

  | __hash__ = None

  在Python解釋器上運(yùn)行help(list)的輸出。

  幫助功能實(shí)際上是使用 pydoc 模塊生成其輸出,它也可以從命令行運(yùn)行,以產(chǎn)生您路徑中任何可導(dǎo)入模塊的文本或 html 表示。

  不久以前,我需要編寫更細(xì)致,更正式的設(shè)計(jì)文檔。而作為一個(gè) Markdown 的粉絲,我決定玩一玩mkdocs,看看是否能獲得我想要的結(jié)果。這個(gè)模塊可以很容易地將你的 markdown 文檔轉(zhuǎn)化為一個(gè)樣式美觀的頁面,并且,在發(fā)布為官方文檔之前,允許你對其做更改。它提供了一個(gè) readthedocs 模板,深圳還提供了一個(gè)簡單的命令行界面,來把你的修改推送到 GitHub Pages 里面。

  在完成了我最初的描述設(shè)計(jì)決策和注意事項(xiàng)的文本后,我想加上一些細(xì)節(jié),描述我正在開發(fā)的實(shí)際接口方法。因?yàn)槲乙呀?jīng)為大部分的功能寫了定義,我想從源代碼自動(dòng)生成參考頁面,還希望這個(gè)能在 markdown 里面。這樣的話,只要我想跑 mkdocs,它就可以連同我文檔的其余部分,一起渲染成 html。

然而,事實(shí)上還沒有一種從源碼生成 markdown 的默認(rèn)方式,除了一些插件。后來,我不斷在谷歌上查詢,我還是不滿意我發(fā)現(xiàn)的插件——很多東西都過時(shí)了,沒有人維護(hù)了,或者輸出的東西不是我需要的——因此,我決定寫一個(gè)我自己的項(xiàng)目。

  “inspect 模塊提供了幾個(gè)有用的函數(shù)來幫助我們獲取生存著的對象信息... ” — Python 文檔

  檢查!

  Inspect,源自于標(biāo)準(zhǔn)程序庫,它不僅允許你查看較低級別的 python 框架和代碼對象,它還提供很多方法來檢查模塊和類,幫你發(fā)現(xiàn)可能感興趣的的項(xiàng)目。這個(gè)也就是之前提到的用來生成幫助文件的 pydoc。

  瀏覽一下在線文檔,你會(huì)發(fā)現(xiàn)許多跟我們所做的嘗試相關(guān)的方法。最重要的幾個(gè)是getmembers()getdoc() signature(),還有許多給 getmembers 做濾波器的 is... 功能。擁有這些,我們可以輕易地循環(huán)訪問很多功能,包括區(qū)分生成器和協(xié)同程序,并可以按需要遞歸到任何一個(gè)類以及內(nèi)部。

  導(dǎo)入編碼

  如果我們要去檢查一個(gè)對象,不管它是什么,第一步要做的是提供一個(gè)導(dǎo)入進(jìn)我們的命名空間的原理。為何要討論導(dǎo)入呢?這取決于你想要做什么,還有很多需要擔(dān)心的,包括虛擬環(huán)境,自定義代碼,標(biāo)準(zhǔn)模塊和重命名。情況會(huì)容易混淆,搞錯(cuò)的話會(huì)需要一些時(shí)間去整理清楚。

  我們當(dāng)然還有些選擇,更復(fù)雜的是直接從pydoc重用 safeimport (),當(dāng)出現(xiàn)問題時(shí),為我們解決很多特例和ErrorDuringImport類的特別條款。然而,如果我們對我們的環(huán)境需要更高的控制,我們自己簡單地運(yùn)行__import__(modulename)也是可能的。

  另一個(gè)需要記住的是每一個(gè)代碼的執(zhí)行路徑??赡軙?huì)用到 sys.path.append() 的一個(gè)目錄來進(jìn)入我們尋找的模塊。我的用例 我的用例是從命令行和被檢查的模塊的路徑中的目錄執(zhí)行,所以,我將當(dāng)前目錄添加到 sys.path,這足以解決典型的導(dǎo)入路徑問題。

  按照上述方式,我們的導(dǎo)入函數(shù)會(huì)如下所示:

  def generatedocs(module):

  try:

  sys.path.append(os.getcwd()) # Attempt import

  mod = safeimport(module) if mod is None:

  print("Module not found")

  # Module imported correctly, let's create the docs

  return getmarkdown(mod) except ErrorDuringImport as e:

  print("Error while trying to import " + module)

  決定輸出

  在繼續(xù)之前,你需要一個(gè)關(guān)于如何組織生成 markdown 輸出的心理圖像。思考:你需要一個(gè)不遞歸到自定義類的淺的引用嗎?我們想要包含哪些方法?內(nèi)置功能會(huì)怎么樣?是用_還是__方法?我們應(yīng)該如何呈現(xiàn)函數(shù)簽名?我們應(yīng)該拉注釋嗎?

  我的選擇如下:

  ·每個(gè)運(yùn)行一個(gè) .md 文件,其中包含遞歸到正在檢查的對象的任意子類中生成的信息。

  ·只包括我創(chuàng)建的自定義代碼,沒有來自導(dǎo)入的模塊的信息。

  ·每一項(xiàng)的輸出必須用第二級 markdown 標(biāo)題(##)標(biāo)識。

  ·所有頭文件必須包含正在描述的項(xiàng)的完整路徑(module.class.subclass.function)。

  ·將完整的函數(shù)簽名作為預(yù)格式化文本。

  ·為每個(gè)標(biāo)題提供錨點(diǎn),以便輕松的鏈接到文檔及文檔本身內(nèi)容。

  ·任何以_或者__開頭的函數(shù)都不做文檔記錄。

  整合在一起

  一旦對象被導(dǎo)入,我們可以開始檢測了。這是一個(gè)簡單的例子,重復(fù)調(diào)用 getmembers(object, filter),過濾器是一個(gè)有用的 is 函數(shù)。你能夠發(fā)現(xiàn) isclass isfunction,其它相關(guān)的方法都是 is開頭的,例如,ismethod , isgenerator , iscoroutine。這都取決于你是否想寫一些通用的,可以處理所有的特殊情況,或一些更小的和更特殊的源代碼。我堅(jiān)持前兩點(diǎn),因?yàn)槲也挥冒巡捎?/span>3個(gè)不同方法來創(chuàng)建我想要的格式化模塊,類和功能。

  def getmarkdown(module):

  output = [ module_header ]

  output.extend(getfunctions(module)

  output.append("***\n")

  output.extend(getclasses(module))

  return "".join(output)def getclasses(item):

  output = list() for cl in inspect.getmembers(item, inspect.isclass): if cl[0] != "__class__" and not cl[0].startswith("_"): # Consider anything that starts with _ private

  # and don't document it

  output.append( class_header )

  output.append(cl[0])

  # Get the docstring

  output.append(inspect.getdoc(cl[1]) # Get the functions

  output.extend(getfunctions(cl[1])) # Recurse into any subclasses

  output.extend(getclasses(cl[1]) return outputdef getfunctions(item): for func in inspect.getmembers(item, inspect.isfunction):

  output.append( function_header )

  output.append(func[0]) # Get the signature

  output.append("\n```python\n)

  output.append(func[0])

  output.append(str(inspect.signature(func[1]))

  # Get the docstring

  output.append(inspect.getdoc(func[1])

  return output

  當(dāng)要格式化大文本和一些編程代碼的混合體時(shí),我傾向于把它作為一個(gè)在列表或元組中的獨(dú)立項(xiàng)目,用 "".join() 來合并輸出。在寫作的時(shí)候,這種方法其實(shí)比基于插值的方法(.format %)更快。然而,python 3.6 的新字符串格式化將比這更快,更具可讀性。

  你可以看到,getmembers() 返回一個(gè)元組與對象的名稱在第一位置和第二位置的實(shí)際對象,我們可以用遞歸遍歷對象層次。

  對于檢索到的每一個(gè)項(xiàng)目,可能使用 getdoc() getcomments() 獲取文檔字符串和注釋。對于每一個(gè)功能,我們可以使用 signature() 得到 Signature 對象 ,它表示其位置參數(shù)和關(guān)鍵字參數(shù)的默認(rèn)值和任何注釋,為我們提供了產(chǎn)生簡單直接的描述和良好風(fēng)格的文本,有助于我們理解用戶我們寫代碼的意圖。

  其他考慮因素和非預(yù)期后果

  請注意,上面的代碼只是示例代碼,只是讓你大概真的最終產(chǎn)品應(yīng)該是什么樣子。在最終確定產(chǎn)品之前,還有很多其他注意事項(xiàng):

  ·getfunctions getclasses 將顯示模塊中導(dǎo)入的所有方法和類。包括內(nèi)置程序包,以及來自外部軟件包的任何東西,所以你必須過濾掉更多的 for 循環(huán)。我在檢查過程中使用模塊的 __file__ 屬性,不管它包含什么項(xiàng)。換句話說,如果項(xiàng)在我正在執(zhí)行的路徑中存在的模塊內(nèi)定義,則包含它(使用 os.path.commonprefix())。

  ·有一些 gotcha 的文件路徑,導(dǎo)入層次結(jié)構(gòu)和名稱。像通過 __init__.py moduleX 導(dǎo)入到包中時(shí),你可以通過 package.moduleX.function 訪問他的函數(shù)方法,但是全稱將會(huì)是 package.moduleX.moduleX.function—通過 moduleX.__name__ 返回的名稱。你或許不在乎這個(gè)區(qū)別,但是我在乎,所以這是在迭代過程中需要記住的事情。

  ·你會(huì)從內(nèi)置程序庫中導(dǎo)入類和任何其他不包含 __file__ 的東西,如果你進(jìn)行任何如上所述的過濾,那么檢查是必要的。

  ·因?yàn)檫@是 markdown,而我們只是導(dǎo)入 docstrings,你可以在你的 docstrings 中包含 mardown 語法,它會(huì)美觀漂亮的呈現(xiàn)在頁面中。然而,這意味著你應(yīng)該注意正確的轉(zhuǎn)義 docstrings,這樣他才不會(huì)破壞生成的 HTML

  示例輸出

  我在 sofi -精確的說是 sofi.app 模塊運(yùn)行生成器,下面是它創(chuàng)建的 markdown 內(nèi)容。

# sofi<a name="sofi"></a><a name="sofi.__init__"></a>### [sofi](#sofi).\_\_init\_\_

```python

__init__(self)

```

<a name="sofi.addclass"></a>

### [sofi](#sofi).addclass```python

addclass(self, selector, cl)```

Add the given class from all elements matching this selector.

  下面是通過 mkdocs 運(yùn)行它產(chǎn)生 readthedocs 主題頁面后的最終結(jié)果(不包括函數(shù)注釋)的示例。

Python文檔編輯器編寫方法步驟詳解 

  我相信你已經(jīng)知道,使用這些機(jī)制自動(dòng)生成文檔,會(huì)生成完整、精確和最新的模塊信息,這些信息在你編寫代碼的時(shí)候可以進(jìn)行維護(hù)和編寫,且操作簡單 。我強(qiáng)烈建議每個(gè)人都試一試。

  在結(jié)束之前,我想再補(bǔ)充一點(diǎn),mkdocs 并不是唯一的文檔包,還有其他一些使用廣泛的系統(tǒng),如 Sphinxmkdocs 基于此開發(fā) )和 Doxygen,他們都能實(shí)現(xiàn)我們以上討論的事項(xiàng)。然而,我比較通過練習(xí)來學(xué)習(xí)和了解更多關(guān)于 Python 內(nèi)部機(jī)制和其隨附的工具。

 

來源:開源中國

您還未登錄,請先登錄

熱門帖子

最新帖子

?