Se ci pensate, oltre al fatto che l'argomento della variabile decompressione scompatta tutto in una volta, c'è anche il fatto che lo format
non necessariamente prende i suoi argomenti in ordine, come in '{2} {1} {0}'
.
Si potrebbe aggirare questo se format
ha appena preso una sequenza invece di richiedere argomenti separati, costruendo una sequenza che fa la cosa giusta. Ecco un esempio banale:
class DefaultList(list):
def __getitem__(self, idx):
try:
return super(DefaultList, self).__getitem__(idx)
except IndexError:
return '-'
Naturalmente la versione vita reale sarebbe avvolgere un iterabile arbitrario, non sottoclasse list
, e probabilmente dovuto usare tee
o una cache interna e tirare in nuovi valori come richiesto, solo inadempiente quando hai passato la fine(Si consiglia di cercare le ricette "lista pigra" o "sequenza lenta" in ActiveState, perché ce ne sono alcune che lo fanno.) Ma questo è sufficiente per mostrare l'esempio.
Ora, come ci aiuta? Non lo fa; *lst
su un DefaultList
proverò a creare una tupla, fornendo esattamente lo stesso numero di argomenti che abbiamo già avuto. Ma cosa succede se avessi una versione di format
che potrebbe semplicemente prendere una sequenza di arg invece? Quindi potresti semplicemente passare il tuo DefaultList
e funzionerebbe.
E questo è quello: Formatter.vformat
.
>>> string.Formatter().vformat('{0} {1} {2}', DefaultList([0, 1]), {})
'0 1 -'
Tuttavia, c'è un modo ancora più semplice, una volta che si sta utilizzando Formatter
esplicitamente invece che implicitamente attraverso il metodo str
. Si può solo sovrascrivere il metodo get_value
e/o la sua 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], {}))
Naturalmente si sta ancora andando ad avere bisogno di avvolgere il vostro iteratore in qualcosa che fornisce il protocollo sequenza.
Mentre noi siamo, il problema potrebbe essere risolto in modo più diretto, se la lingua ha avuto un protocollo "iterabile disimballaggio". Vedi here per un thread di idee in python che propone una cosa del genere e tutti i problemi che l'idea ha. (Si noti inoltre che la funzione format
renderebbe questo più complicato, poiché sarebbe necessario utilizzare direttamente il protocollo di decompressione invece di affidarsi all'interprete per eseguirlo magicamente, ma, supponendo che lo facesse, sarebbe sufficiente scrivere un involucro semplice e generico intorno a qualsiasi iterable che gestisce __unpack__
per esso.)
Capito. Puoi suggerire un approccio migliore? Non sono contento di produrre un generatore di una lunghezza massima, che è uno spreco (vanifica lo scopo di usare un generatore, una lista farebbe) e non sarebbe garantito che funzioni sempre. – user443854
@ user443854: È possibile utilizzare 'itertools.islice()' per limitare un generatore. –
Sono a conoscenza di 'itertools.islice()', ma non vedo come si applica qui. Avrei bisogno di conoscere il numero di elementi necessari prima che io possa usarlo. Speravo di ottenere qualcosa di diverso. In parole povere, voglio dire all'interprete: ecco un generatore, ripetilo tutte le volte che è necessario, ma non di più. – user443854