Python的動(dòng)態(tài)重新封裝的教程
讓我們描繪一下本文的情節(jié):假設(shè)您要在本地機(jī)器上運(yùn)行一個(gè)進(jìn)程,而部分程序邏輯卻在另一處。讓我們特別假設(shè)這個(gè)程序邏輯會(huì)不時(shí)更新, 而您運(yùn)行進(jìn)程時(shí),希望使用最新的程序邏輯。有許多方法可以滿(mǎn)足剛提到的要求;本文將向您說(shuō)明其中幾種方法。
隨著“可愛(ài)的 Python”專(zhuān)欄不斷進(jìn)行,已經(jīng)討論了我的公共域?qū)嵱贸绦?Txt2Html 的正在進(jìn)行的增強(qiáng)。該實(shí)用程序?qū)ⅰ爸悄?ASCII”文本文件轉(zhuǎn)換成 HTML。以前的文章討論了實(shí)用程序的 Web 代理版本和實(shí)用程序的 curses 界面。同樣,我偶爾注意到可以用更有效的方法轉(zhuǎn)換某些 ASCII 標(biāo)記,或者解決了一個(gè)在處理某個(gè)特殊標(biāo)記結(jié)構(gòu)中的錯(cuò)誤。
事實(shí)上,本專(zhuān)欄的文章都是用 ASCII 編寫(xiě)的,然后在編輯過(guò)程中轉(zhuǎn)換成您可以閱讀的 HTML 格式。在發(fā)表文章草稿之前,我運(yùn)行了類(lèi)似以下處理的程序:
文章的命令行 HTML 化
txt2html charming_python_7.txt > charming_python_7.html
如果愿意,我可以指定一些標(biāo)志來(lái)修改操作;但不管怎樣,事實(shí)上轉(zhuǎn)換器的最新版本在我的本地驅(qū)動(dòng)器和路徑中。如果在另一臺(tái)機(jī)器上工作,或者對(duì)于要使用該實(shí)用程序的讀者,則過(guò)程比較麻煩:請(qǐng)?jiān)L問(wèn)我的網(wǎng)站,注意比較版本號(hào)和文件日期(有時(shí)更改太小,我不會(huì)更改版本號(hào)),下載當(dāng)前版本、將當(dāng)前版本復(fù)制到正確目錄,然后運(yùn)行命令行轉(zhuǎn)換器。(請(qǐng)參閱本文后面的 參考資料。)
以上的過(guò)程包括幾個(gè)需要手工操作且比較費(fèi)時(shí)的步驟。應(yīng)該更簡(jiǎn)單,而且可以做到這點(diǎn)。
命令行 Web 訪問(wèn)
大多數(shù)人認(rèn)為 Web 是在 GUI 環(huán)境中交互式瀏覽頁(yè)面的一種方法。那樣做當(dāng)然很好,但命令行中也有許多功能。帶文本模式 Web 瀏覽器 lynx 的系統(tǒng)完全可以將整個(gè) Web 看作是命令行工具使用的另一個(gè)文件集。例如,我發(fā)現(xiàn)有些命令很有用:
使用 lynx 進(jìn)行命令行 Web 瀏覽
lynx -dump http://gnosis.cx/publish/. lynx -dump http://ibm.com/developerworks/. > ibm_developer.txt lynx -dump http://gnosis.cx/publish | wc | sed "s/( *[0-9]* *\)\([0-9]*\)\(.*\)/\2/g"
第一行說(shuō):“將 David Mertz 的主頁(yè)(以 ASCII 文本)顯示到控制臺(tái)?!钡诙姓f(shuō):“將 IBM 的當(dāng)前 developerWorks 主頁(yè)的 ASCII 版本保存到文件?!钡谌惺纠f(shuō):“顯示 David 主頁(yè)的字?jǐn)?shù)?!保ú槐?fù)?dān)心細(xì)節(jié),它只顯示與管道結(jié)合的命令行工具。)
關(guān)于 lynx,有一點(diǎn)要注意它(使用 -dump 選項(xiàng)時(shí))執(zhí)行幾乎與 Txt2Html 完全相反的操作:前一種工具將 HTML 轉(zhuǎn)換成文本;而后一種工具則轉(zhuǎn)換成其它格式。但沒(méi)有理由不使用與 lynx 一樣流行的 Txt2Html??梢允褂靡粋€(gè)很短的 Python 腳本完成這個(gè)操作:
'fetch_txt2html.py' 命令行轉(zhuǎn)換器
import sys
from urllib import urlopen, urlencode
if len(sys.argv) == 2:
cgi = 'http://gnosis.cx/cgi/txt2html.cgi'
opts = urlencode({'source':sys.argv[1], 'proxy':'NONE'})
print urlopen(cgi, opts).read()
else:
print "Please specify URL for Txt2Html conversion"
要運(yùn)行這個(gè)腳本,只要執(zhí)行如下操作:
python fetch_txt2html.py http://gnosis.cx/publish/programming/charming_python_7.txt
這并沒(méi)有向您提供本地 Txt2Html 處理的全部開(kāi)關(guān),但如有必要,添加它們也很容易??梢韵袷褂萌魏蚊钚泄ぞ咭粯觼?lái)輸送和重定向輸出。但是,在上述版本中,只能處理 URL 可以到達(dá)的數(shù)據(jù)文件,而不能處理本地文件。
實(shí)際上, fetch_txt2html.py 可以完成 lynx 不能完成的任務(wù)(Txt2Html 本身也不能):它不僅從 URL 取得數(shù)據(jù)源,而且還遠(yuǎn)程獲取 程序邏輯 。如果使用 fetch_txt2html.py ,就 不必在本地機(jī)器上安裝 Txt2Html;將(使用最新版本)遠(yuǎn)程調(diào)用處理,并且將把結(jié)果發(fā)送回來(lái),就像運(yùn)行的是本地進(jìn)程。很棒吧?Txt2Html 的本地版本可以訪問(wèn)遠(yuǎn)程 URL,就像訪問(wèn)本地文件一樣,但它還不能保證它自身是最新的……!
動(dòng)態(tài)初始化
使用 fetch_txt2html.py 確保了在轉(zhuǎn)換中始終使用最新的程序邏輯。但是,這個(gè)方法可以完成的另一件事情是將處理器(和內(nèi)存)的需求轉(zhuǎn)移給 gnosis.cx Web 服務(wù)器。此特殊進(jìn)程的負(fù)載并不是特別高,但人們卻很可能認(rèn)為在客戶(hù)機(jī)上處理的其它類(lèi)型的進(jìn)程會(huì)更有效且令人滿(mǎn)意。
組織 Txt2Html 的方式 -- 也就是組織大多數(shù)程序的方式 -- 是用一些由各種實(shí)用函數(shù)提供的核心流量控制函數(shù)。尤其是這些實(shí)用函數(shù)是一些經(jīng)常更新的函數(shù);核心函數(shù)( main() 和一些其它函數(shù))只有在做重大改寫(xiě)時(shí)才會(huì)變動(dòng)??偠灾?,在每個(gè)程序運(yùn)行時(shí)有效更新的就是實(shí)用函數(shù)。其實(shí),大部分情況下,主 Txt2Html 模塊 dmTxt2Html 中的大多數(shù)函數(shù)就夠了。
'd2h_textfuncs.py' 動(dòng)態(tài) Txt2Html 更新
"""Hot-pluggable replacement functions for Txt2Html"""
#-- Functions to massage blocks by type
#def
Titleify(block):
#def Authorify(block):
# ... [more block massaging functions] ...
#-- Utility functions for text transformation
#def AdjustCaps(txt):
#def capwords(txt):
#def URLify(txt):
def Typographify
(txt):
# [module] names
r = re.compile(r
""'([\(\s'/">]|^)\[(.*?)\]([<\s\.\),:;'"?!/-])""" , re.M | re.S)
txt = r.sub(
'\\1<em><code>\\2</code></em>\\3' ,txt)
# *strongly emphasize* words
r = re.compile(r
""'([\(\s'/"]|^)\*(.*?)\*([\s\.\),:;'"?!/-])""" , re.M | re.S)
txt = r.sub(
'\\1<strong>\\2</strong>\\3' , txt)
# ... [more text massaging] ...
return
txt
# ... [more text transformation functions] .....
要使用最新和最具體的支持模塊,需要一些準(zhǔn)備步驟。首先,將主 Txt2Html 模塊下載到本地系統(tǒng)(這是一次性步驟)。其次,在本地系統(tǒng)上創(chuàng)建類(lèi)似于以下示例的 Python 腳本:
'dyn_txt2html.py' 命令行轉(zhuǎn)換器
from
dmTxt2Html
import
*
# Import the body of 'Txt2Html' code
from
urllib
import
urlopen
import
sys
# Check for updated functions (fail gracefully if not fetchable)
try
:
updates = urlopen(
'http://gnosis.cx/download/t2h_textfuncs.py' ).read()
fh = open(
't2h_textfuncs.py' ,
'w' )
fh.write(updates)
fh.close()
except
:
sys.stderr.write(
'Cannot currently download Txt2Html updates' )
# Import the updated functions (if available)
try
:
from
t2h_textfuncs
import
*
except
:
sys.stderr.write(
'Cannot import the updated Txt2Html functions' )
# Set options based on runmode (shell vs. CGI)
if
len(sys.argv) >= 2:
cfg_dict = ParseArgs(sys.argv[1:])
main(cfg_dict)
else
:
print"Please specify URL (and options) for Txt2Html conversion"
在 dyn_txt2html.py 腳本中,請(qǐng)注意當(dāng)執(zhí)行 from t2h_textfuncs import * 語(yǔ)句時(shí),所有以前在 dmTxt2Html 中定義的函數(shù)(如 Typographify() )都將由 t2h_textfuncs 版本的同名函數(shù)替換。當(dāng)然,如果 t2h_textfuncs 的函數(shù)被注釋掉了,則不會(huì)被替換。
有件小問(wèn)題得注意,不同的系統(tǒng)以不同的方式處理寫(xiě)入 STDERR。在類(lèi) UNIX 系統(tǒng)中,運(yùn)行腳本時(shí)可以重定向 STDERR;但是在當(dāng)前 OS/2 外殼和 Windows/DOS 中,STDERR 消息將附加到控制臺(tái)輸出。您也許要將以上的錯(cuò)誤/警告寫(xiě)到日志文件中,或者只習(xí)慣于將 STDOUT 定向到文件(可能會(huì)更有用)。例如:
'dyn_txt2html' 的命令行會(huì)話(huà)
G:\txt2html> python dyn_txt2html.py test.txt > test.html Cannot currently download Txt2Html updates
錯(cuò)誤轉(zhuǎn)至控制臺(tái);經(jīng)轉(zhuǎn)換的輸出轉(zhuǎn)至文件。
一件更有趣的事情是 dyn_txt2html.py 為什么不下載整個(gè) dmTxt2Html 模塊,而僅下載支持模塊。當(dāng)然這是有理由的。 t2h_textfuncs 支持模塊遠(yuǎn)遠(yuǎn)小于主 dmTxt2Html 模塊,特別是因?yàn)榇蠖鄶?shù)函數(shù)已經(jīng)過(guò)刪節(jié)/被注釋掉。在調(diào)制解調(diào)器連接上,它的速度明顯快很多。但下載大小并不是主要原因。
對(duì)于 Txt2Html,如果用戶(hù)自動(dòng)下載整個(gè)最新模塊也沒(méi)關(guān)系。但程序邏輯是 分布式 的系統(tǒng)(特別是維護(hù)責(zé)任也是分布式的)會(huì)發(fā)生什么情況呢?您也許會(huì)讓 Alice、Bob 和 Charlie 分別負(fù)責(zé)模塊 Funcs_A 、 Funcs_B 和 Funcs_C 。他們每個(gè)人都對(duì)他們負(fù)責(zé)的函數(shù)進(jìn)行定期(且獨(dú)立)更改,并將最新和最好的版本上傳到他們自己的網(wǎng)站(如 http://alice.com/Funcs_A.py)。在這種情況下,讓三個(gè)程序員都更改同一個(gè)主模塊不太可行。但可以直接擴(kuò)展類(lèi)似于 dyn_txt2html.py 的腳本以在啟動(dòng)時(shí)嘗試導(dǎo)入 Funcs_A 、 Funcs_B 和 Funcs_C (如果不能獲取這些資源,則會(huì)退到 MainProg 版本)。
長(zhǎng)期運(yùn)行的動(dòng)態(tài)進(jìn)程
迄今為止,我們研究的工具已經(jīng)通過(guò)在初始化時(shí)下載更新資源而獲得了動(dòng)態(tài)程序邏輯。這對(duì)于命令行處理或批處理很有意義,但對(duì)于長(zhǎng)期運(yùn)行的應(yīng)用程序又會(huì)怎樣。這種長(zhǎng)期運(yùn)行的應(yīng)用程序最可能是一些不斷響應(yīng)客戶(hù)機(jī)請(qǐng)求的服務(wù)器進(jìn)程。但是在這個(gè)案例中,我們將使用為 以前的文章 開(kāi)發(fā)的 curses_txt2html.py 來(lái)說(shuō)明 Python 的 reload() 函數(shù)。程序 curses_txt2html 是 dmTxt2Html 本地副本的封裝器。這里并不是第二次提到 curses 編程,談一下 curses_txt2html 提供了一組交互式菜單以配置和運(yùn)行多個(gè)連續(xù)的 Txt2Html 轉(zhuǎn)換也足夠了。
curses_txt2html 可以一直在后臺(tái)運(yùn)行,當(dāng)切換到它的會(huì)話(huà)并運(yùn)行轉(zhuǎn)換時(shí),我們希望它能夠使用最新的程序邏輯。對(duì)于這個(gè)特定的簡(jiǎn)單示例,關(guān)閉和重新啟動(dòng)應(yīng)用程序并不難,并不會(huì)帶來(lái)特別的損害。但這很容易令人聯(lián)想到其它一直運(yùn)行著的進(jìn)程(可能是說(shuō)明會(huì)話(huà)中所執(zhí)行操作狀態(tài)的進(jìn)程)。
在本文中,添加了新的 File/Update 子菜單。它被激活時(shí)只調(diào)用新的函數(shù) update_txt2html() 。除了與提供發(fā)生的確認(rèn)相關(guān)的 curses 調(diào)用之外,我們已經(jīng)在本文的其它示例中看到過(guò)這些步驟:
'curses_txt2html.py' 動(dòng)態(tài)更新函數(shù)
def update_txt2html
():
# Check for updated functions (fail gracefully if not fetchable)
s = curses.newwin(6, 60, 4, 5)
s.box()
s.addstr(1, 2,
"* PRESS ANY KEY TO CONTINUE *" , curses.A_BOLD)
s.addstr(3,2,
"...downloading..." )
s.refresh()
try
:
from
urllib
import
urlopen
updates = urlopen(
'http://gnosis.cx/download/dmTxt2Html.py' ).read()
fh = open(
'dmTxt2Html.py' ,
'w' )
fh.write(updates)
fh.close()
s.addstr(3,2,
"Module [dmTxt2Html] downloaded to current directory" )
except
:
s.addstr(3,2,
"Download of updated [dmTxt2Html] module failed!" )
reload(dmTxt2Html)
s.addstr(4, 2,
"Module [dmTxt2Html] reloaded from current directory " )
s.refresh()
c = s.getch()
s.erase()
dyn_txthtml.py 和 update_txt2html() 函數(shù)之間有兩個(gè)重要差異。其中一個(gè)差異是繼續(xù)操作,并導(dǎo)入主 dmTxt2Html 模塊而不只導(dǎo)入支持函數(shù)。這主要是簡(jiǎn)化了導(dǎo)入。這里的問(wèn)題是我們使用 import dmTxt2Html 來(lái)訪問(wèn)模塊,而不是 from dmTxt2Html import * 。從許多方面考慮,這是一個(gè)更安全的過(guò)程,但結(jié)果是使覆蓋 dmTxt2Html 中的函數(shù)變得更困難(不論是無(wú)心地還是故意地)。如果我們要從 d2h_textfuncs 附加函數(shù),則必須對(duì)導(dǎo)入的支持模塊執(zhí)行 dir() ,并將成員以屬性形式附加到 "dmTxt2Html" 名稱(chēng)空間。執(zhí)行這種樣式的覆蓋是留給讀者的練習(xí)。
update_txt2html() 函數(shù)帶來(lái)的最主要差異是 Python 的內(nèi)置 reload() 函數(shù)的用法。只執(zhí)行全新的 import dmTxt2Html 將 不 會(huì)覆蓋以前導(dǎo)入的函數(shù)。請(qǐng)密切注意這一點(diǎn)!許多初學(xué)者認(rèn)為重新導(dǎo)入模塊將更新內(nèi)存中的版本。這是錯(cuò)的。實(shí)際上,更新模塊中函數(shù)的內(nèi)存映像的方法是 reload() 模塊。
以上示例中還執(zhí)行了另一個(gè)小技巧。更新 dmTxt2Html 模塊的下載位置是本地工作目錄,而這個(gè)目錄可能是(也可能不是)原來(lái)裝入 dmTxt2Html 的目錄。事實(shí)上,如果它在 Python 庫(kù)目錄中,那么您也許不在該目錄中使用(也許對(duì)它沒(méi)有用戶(hù)許可權(quán))。但 reload() 調(diào)用嘗試先從當(dāng)前目錄裝入,然后再?lài)L試 Python 路徑的其余部分。所以,不論下載是否成功, reload() 應(yīng)該是一個(gè)安全的操作(雖然它可能裝入新的模塊,也可能不裝入)。
- 從零學(xué)python系列之淺談pickle模塊封裝和拆封數(shù)據(jù)對(duì)象的方法
- 基于python3 類(lèi)的屬性、方法、封裝、繼承實(shí)例講解
- Python數(shù)據(jù)操作方法封裝類(lèi)實(shí)例
- Python封裝shell命令實(shí)例分析
- Python面向?qū)ο笾^承和組合用法實(shí)例分析
- Python面向?qū)ο笾涌凇⒊橄箢?lèi)與多態(tài)詳解
- Python面向?qū)ο笾o態(tài)屬性、類(lèi)方法與靜態(tài)方法分析
- Python面向?qū)ο笾瓷?自省機(jī)制實(shí)例分析
- Python封裝原理與實(shí)現(xiàn)方法詳解
相關(guān)文章
詳解如何從TensorFlow的mnist數(shù)據(jù)集導(dǎo)出手寫(xiě)體數(shù)字圖片
這篇文章主要介紹了詳解如何從TensorFlow的mnist數(shù)據(jù)集導(dǎo)出手寫(xiě)體數(shù)字圖片,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
利用Python實(shí)現(xiàn)RSA加密解密方法實(shí)例
過(guò)去幾天我一直在嘗試用Python實(shí)現(xiàn)RSA算法,下面這篇文章主要給大家介紹了關(guān)于利用Python實(shí)現(xiàn)RSA加密解密的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04
python數(shù)據(jù)批量寫(xiě)入ScrolledText的優(yōu)化方法
今天小編就為大家分享一篇python數(shù)據(jù)批量寫(xiě)入ScrolledText的優(yōu)化方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-10-10
pycharm三個(gè)有引號(hào)不能自動(dòng)生成函數(shù)注釋的問(wèn)題
這篇文章主要介紹了解決pycharm三個(gè)有引號(hào)不能自動(dòng)生成函數(shù)注釋的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02

