2013-10-23 7 views
8

Io di solito uso il seguente schema (come indicato nel this question):abbreviazione di String.Format (..., ** locals())

a=1 
s= "{a}".format(**locals()) 

Penso che sia un ottimo modo per scrivere facilmente leggibile codice.

A volte è utile per formati di stringa "catena", al fine di "rendere modulare" la creazione di stringhe complesse:

a="1" 
b="2" 
c="{a}+{b}".format(**locals()) 
d="{c} is a sum".format(**locals()) 
#d=="1+2 is a sum" 

Abbastanza presto, il codice è importunano con X.format(**locals()). Per risolvere questo problema, ho cercato di creare un lambda:

f= lambda x: x.format(**locals()) 
a="1" 
b="2" 
c= f("{a}+{b}") 
d= f("{c} is a sum") 

ma questo getta un KeyError, dal momento che locals() sono i locali del lambda.

Ho anche cercato di applicare il formato solo nell'ultima stringa:

a="1" 
b="2" 
c="{a}+{b}" 
d="{c} is a sum".format(**locals()) 
#d=="{a}+{b} is a sum" 

Ma questo non funziona, dal momento pitone formatta solo una volta. Ora, io potrei scrivere una funzione che formatta ripetutamente fino a quando non c'è più nulla da fare:

def my_format(string, vars): 
    f= string.format(**vars) 
    return f if f==string else my_format(f, vars) 

ma mi chiedo: c'è un modo migliore per fare questo?

risposta

4

f = lambda x, l=locals(): x.format(**l) sembra funzionare ...

e se si voleva una versione che è un po 'più totalizzante (e probabilmente molto più lento):

fg = lambda x, l=locals(), g=globals(): x.format(**dict(g.items() + l.items())) 

troveranno i simboli in entrambe le locali o globali.

+0

Probabilmente vuoi che i locali scavalchino i globali. Attualmente, lo hai fatto al contrario, dal momento che gli argomenti successivi per vincere. – Collin

+0

buon punto ... farò quel cambiamento. –

0

Non è una battuta, ma funziona:

def fmt(s, l=locals()): 
    while '{' in s: 
     s = s.format(**l) 
    return s 

a="1" 
b="2" 
c="{a}+{b}" 
d="{c} is a sum" 

print fmt(d) # 1+2 is a sum 

Ecco una sola riga (e un po 'meno efficiente) versione ricorsiva:

fmt = lambda s, l=locals(): fmt(s.format(**l), l=l) if '{' in s else s 
2

Se avete solo bisogno di fare questo entro l'ambito della funzione come collegamento locale, il seguente funzionerà:

def formatter(fmt, loc=locals()): 
    return fmt.format(**loc) 

Tuttavia, questo vincolerà il valore ret urlato da locals() al momento della dichiarazione di funzione, piuttosto che di esecuzione, quindi non verrà aggiornato come i valori cambiano, né sarà utile quando chiamato da qualsiasi altro ambito.

Se si desidera ottenere l'accesso a quello del locals metodo di chiamata, è necessario inspect lo stack di chiamate (http://docs.python.org/2/library/inspect.html)

import inspect 

def formatter(fmt): 
    parent = inspect.stack()[1][0] # 1 = the previous frame context 
            # 0 = the frame object 
    return fmt.format(**parent.f_locals) 

Si noti che questo non può funzionare per implementazioni di Python che non sono CPython.

ora si può fare:

a = "1" 
b = "2" 
c = formatter("{a}+{b}") 
d = formatter("{c} is a sum") 
+0

in realtà, questo è vero a volte, ma non sempre ... sembra che la gente del posto() restituisca effettivamente un puntatore al valore di "locals", che sembra cambiare. Puoi fare i seguenti esperimenti: 'f = locals(); x = 1; g = locali(); f == g', che sarà True, anche se hai modificato un valore locale tra f e g. Inoltre: 'def fn (x, l = locals()): print l [x]; x = 2; fn ('x'); x = 3; fn ('x') 'stamperà 2, quindi 3. Sembra che dovrebbe essere vero qualche volta, quindi è un buon commento, ma sembra che ci siano molti casi pratici in cui puoi ignorarlo. –