學習《Python Cookbook》第三版
Python 並沒有對在字串中簡單替換變數值提供直接的支援。但是透過使用字串的 format() 方法來解決這個問題。比如:
my_text = '{name} has {number} dogs'print(my_text.format(name='Cory', number=3)) # 'Cory has 3 dogs'
或者,如果要被替換的變數能在變數域中找到,那麼你可以結合使用 format_map()和 vars() 。就像下面這樣:
name = 'Cory'number = 3my_text = '{name} has {number} dogs'print(my_text.format_map(vars())) # 'Cory has 3 dogs'
vars() 還有一個有意思的特性就是它也適用於物件例項。比如:
class Person(object): def __init__(self, name, num): self.name = name self.num = nummy_text_1 = '{name} has {num} dogs'person = Person('Cory', 3)print(my_text_1.format_map(vars(person))) # 'Cory has 3 dogs'
官方對vars()的解釋:
vars([object])
Return the__dict__ attribute for a module, class, instance, or any other object with a __dict__ attribute.
Objects such as modules and instances have an updateable __dict__ attribute; however, other objects may have write restrictions on their __dict__ attributes (for example, classes use a types.MappingProxyType to prevent direct dictionary updates).
Without an argument, vars() acts like locals(). Note, the locals dictionary is only useful for reads since updates to the locals dictionary are ignored.
返回模組,類,例項或具有__dict__屬性的任何其他物件的__dict__屬性。
諸如模組和例項之類的物件具有可更新的__dict__屬性; 但是,其他物件可能對其__dict__屬性具有寫限制(例如,類使用type.MappingProxyType來防止字典直接更新)。
函式不帶引數,vars()就像locals()一樣。 請注意,本地字典僅對讀取有用,忽略了本地字典的更新。
官方對format_map()的解釋:
str.format_map(mapping)
Similar to str.format(**mapping), except that mapping is used directly and not copied to a dict.
與str.format(**mapping)相似,除了直接使用對映而不將其複製到dict。 如果對映是dict的子類,這將很有用.
class DefaultPerson(dict): def __missing__(self, key): return keymy_text_1 = '{name} has {num} dogs'person = DefaultPerson(name='Cory')print(my_text_1.format_map(person)) # 'Cory has num dogs'
format 和 format map() 的一個缺陷就是它們並不能很好的處理變數缺失的情況,比如:
一種避免這種錯誤的方法是另外定義一個含有 missing () 方法的字典物件,就像上面那樣
如果你發現自己在程式碼中頻繁的執行這些步驟,你可以將變數替換步驟用一個工具函式封裝起來。就像下面這樣:
my_text_1 = '{name} has {num} dogs'class Default(dict): def __missing__(self, key): return keydef sub(text): return text.format_map(Default(sys._getframe(1).f_locals))name = 'Cory'num = 3print(sub(my_text_1)) # 'Cory has 3 dogs'print(sub('{name} has {num} dogs, but has {cat_num} cats')) # 'Cory has 3 dogs, but has cat_num cats'
而對於sys._getframe()的用法可以參考如下例子,如果有興趣瞭解具體調取堆疊資訊,我們後續可以進行詳細瞭解:
import sysdef first(): second()def second(): third()def third(): layer = 0 while True: try: frame = sys._getframe(layer) show_frame(layer, frame) layer += 1 except ValueError: breakdef show_frame(num, frame): print(frame) print(' frame = sys._getframe({})'.format(num)) print(' function = {}()'.format(frame.f_code.co_name)) print(' file/line = {}:{}'.format(frame.f_code.co_filename, frame.f_lineno))first()
多年以來由於 Python 缺乏對變數替換的內建支援而導致了各種不同的解決方案。作為本節中展示的一個可能的解決方案,你可以有時候會看到像下面這樣的字串格式化程式碼:
name = 'Cory'num = 3print('%(name)s has %(num)d dogs.' % vars()) # 'Cory has 3 dogs.'
你可能還會看到字串模板的使用:
import stringname = 'Cory'num = 3my_text_temp = string.Template('$name has $num dogs.')print(my_text_temp.substitute(vars())) # 'Cory has 3 dogs.'
然而, format() 和 format map() 相比較上面這些方案而已更加先進,因此應該被優先選擇。使用 format() 方法還有一個好處就是你可以獲得對字串格式化的所有支援 (對齊,填充,數字格式化等待),而這些特性是使用像模板字串之類的方案不可能獲得的。
本機還部分介紹了一些高階特性。對映或者字典類中鮮為人知的__missing__() 方法可以讓你定義如何處理缺失的值。在Default類中,這個方法被定義為對缺失的值返回一個佔位符。你可以發現缺失的值會出現在結果字串中 (在除錯的時候可能很有用),而不是產生一個 KeyError 異常。
sub() 函式使用 sys._getframe(1) 返回呼叫者的堆疊。可以從中訪問屬性f_locals 來獲得區域性變數。毫無疑問絕大部分情況下在程式碼中去直接操作堆疊應該是不推薦的。但是,對於像字串替換工具函式而言它是非常有用的。另外,值得注意的是 f_locals 是一個複製呼叫函式的本地變數的字典。儘管你可以改變 f_locals的內容,但是這個修改對於後面的變數訪問沒有任何影響。所以,雖說訪問一個堆疊看上去很邪惡,但是對它的任何操作不會覆蓋和改變呼叫者本地變數的值。