Recipe 1.9. Simplifying Usage of Strings' translate Method
Recipe 1.9. 簡化字串 translate 方法的用法
Credit: Chris Perkins, Raymond Hettinger
問題
您常常希望使用高效的字串 translate 方法,但卻很難記住該方法和 string.maketrans 函數的詳細用法,因此您想要一種能在通常情況下簡化其用法的封裝方案(facade)。
解法
正如 Recipe 1.10 中所述,字串的 translate 方法非常強大切頗具伸縮性。然而恰恰是因為這種強大威力和延展性所帶來的使用難度,使得我們似乎有必要使用一種“封裝方案(facade)”為其添加一個前端介面,以便簡化其在通常情況下的用法:
import string
def translator(frm='', to='', delete='', keep=None):
if len(to) == 1:
to = to * len(frm)
trans = string.maketrans(frm, to)
if keep is not None:
allchars = string.maketrans('', '')
delete = allchars.translate(allchars, keep.translate(allchars, delete))
def translate(s):
return s.translate(trans, delete)
return translate
討論
我常常發現自己想要使用字串的 translate 方法來做些事情,但每次我都不得不停下來仔細回想其詳細用法(請參見 Recipe 1.10 查看更多關於詳細用法的資訊)。因此我自己編寫了一個 class(之後又將其重製為 factory closure ,即本條目“解法”中所呈現的方案),將多種可能的處理封裝到一個較為簡易的 facade 當中。現如今,若我想要一個函數,使其只保留給定集合中的字元,我就可以簡單地建構並使用這個函數:
>>> digits_only = translator(keep=string.digits)
>>> digits_only('Chris Perkins : 224-7992')
'2247992'
若要從字串中移除某個字元集中的字元,也同樣簡單:
>>> no_digits = translator(delete=string.digits)
>>> no_digits('Chris Perkins : 224-7992')
'Chris Perkins : -'
若要用單一個字元替換一個字元集合,可以這樣做:
>>> digits_to_hash = translator(from=string.digits, to='#')
>>> digits_to_hash('Chris Perkins : 224-7992')
'Chris Perkins : ###-####'
雖然上面這個用法可能看起來有點特殊,但於我而言確為時不時就會出現的任務。
在本條目中,我不得不作出一個帶有隨意性的設計決定,即在 delete 參數與 keep 參數交疊的情況下,讓 delete 參數“吃掉”keep 參數:
>>> trans = translator(delete='abcd', keep='cdef')
>>> trans('abcdefg')
'ef'
對於您自己的應用而言,在指定了 keep 的情況下,或許忽略 delete 更好;而在兩者同時被指定的情況下,或許最好是拋出異常(因為在同一個 translator 調用中同時指定兩者畢竟沒有多大實際意義)。同樣,如 Recipe 1.8 和 Recipe 1.10 所述,本條目中的代碼僅適用於一般字元串,不適用於 Unicode 字串,因為 Unicode 字串的 translate 方法與一般字元串(即以 byte 為處理單位的字串)的同名方法有所區別。
---- BOX BEGIN ----
Closures
Closure 並沒有複雜到可怕的地步:它只是一個“內部”函數,指代“包含該函數的那個‘外部’函數的本地名稱(即變數)”。下面是個陽春的例子:
def make_adder(addend):
def adder(augend): return augend+addend
return adder
執行 p = make_adder(23) 就會製造出一個 closure ,即內建函式 adder ,其指代一個被綁定為數值 23 的名稱。接著,q = make_adder(42) 又製造出一個 closure ,其內的 addend 被綁定到數值 42。此時 q 與 互不干涉,兩者可以愉快且獨立地共生。如此一來,我們就可以執行諸如 pprint p(100), q(100) 這樣的語句,並得到結果為 123 142 的輸出。
在實際當中,您可能常常會看到,make_adder 會被看作 closure ,而不是以帶有學究氣的、生硬冗長的“返回 closure 的函數”來解釋。幸運的是,上下文經常能夠明晰具體情況。將 make_adder 稱為 factory (或 factory function ,工廠函數)既準確又精鍊;您還可以說它是 closure factory ,以便闡明它建造並返回 closures 的事實,而不是 class 或 class instances 。
---- BOX E N D ----
請參見
Recipe 1.10 包括本條目中 translate(keep=...) 的等價方案、更多關於 translate 方法的資訊,以及適用於 Unicode 字串的等價方案;在 Library Reference 和 Python in a Nutshell 中關於字串 translate 方法以及 string 模組中的 maketrans 函數的文檔。