如果你仔細想想,除了可變參數解包全部解包的事實之外,還有一個事實,即format
不一定按順序參數化參數,如'{2} {1} {0}'
。
如果format
只需要一個序列而不需要單獨的參數,那麼可以通過構建一個正確的序列來解決此問題。這裏有一個簡單的例子:
class DefaultList(list):
def __getitem__(self, idx):
try:
return super(DefaultList, self).__getitem__(idx)
except IndexError:
return '-'
當然,您的真實版本將包裹任意迭代,而不是繼承list
,並有可能不得不使用tee
或內部緩存和新的價值觀拉的要求,只有違約當你通過結束。(你可能想在ActiveState中搜索「lazy list」或「lazy sequence」食譜,因爲有一些這樣做。)但這足以證明這個例子。
現在,這對我們有什麼幫助?它不; *lst
上的DefaultList
只會試圖將一個元組從事件中提供給我們完全相同數量的我們已經擁有的參數。但是如果你有一個版本爲format
的版本,那麼它可能只需要一系列參數呢?那麼你可以通過你的DefaultList
,它會工作。
而你確實有:Formatter.vformat
。
>>> string.Formatter().vformat('{0} {1} {2}', DefaultList([0, 1]), {})
'0 1 -'
然而,有一個更簡單的方法,一旦你使用Formatter
明確,而不是隱含通過str
方法。你可以只覆蓋其get_value
方法和/或其check_unused_args
:
class DefaultFormatter(string.Formatter):
def __init__(self, default):
self.default = default
# Allow excess arguments
def check_unused_args(self, used_args, args, kwargs):
pass
# Fill in missing arguments
def get_value(self, key, args, kwargs):
try:
return super(DefaultFormatter, self).get_value(key, args, kwargs)
except IndexError:
return '-'
f = DefaultFormatter('-')
print(f.vformat('{0} {2}', [0], {}))
print(f.vformat('{0} {2}', [0, 1, 2, 3], {}))
當然,你仍然會需要來包裝你的迭代器的東西,它提供的序列協議。
雖然我們在這樣做,但如果語言有一個「可迭代拆包」協議,則可以更直接地解決問題。請參閱here瞭解提議這樣的事情的python-ideas線程,以及這個想法所具有的所有問題。 (另外請注意,format
函數會讓這個技巧更棘手,因爲它必須直接使用解包協議,而不是依靠解釋器來神奇地完成它。但是,假設它這樣做了,那麼你只需要寫一個非常簡單的任何可處理__unpack__
的iterable都是簡單和通用的包裝。)
明白了。你能提出一個更好的方法嗎?我對產生一些最大長度的發電機並不滿意,這是浪費的(破壞了使用發電機的目的,列表會這樣做),並且不能保證總能正常工作。 – user443854
@ user443854:您可以使用'itertools.islice()'來限制一個生成器。 –
我知道'itertools.islice()',但我不明白它在這裏如何應用。在使用它之前,我需要知道所需的元素數量。我希望能取得不同的成就。用簡單的英語,我想告訴解釋者:這是一個生成器,根據需要多次迭代它,但不會更多。 – user443854