2015-03-24 9 views
8

Attualmente sto costruendo un'applicazione in cui ho bisogno di scorrere su una serie di passaggi che fanno in gran parte la stessa cosa, salvo una quantità molto piccola di codice (~ 15 linee). Il numero di passaggi varierà a seconda di come è configurato il progetto, quindi mi sembra un po 'sciocco creare una funzione separata per ogni potenziale istanza.Memorizzazione di funzioni nel dizionario [Python]

In JavaScript, vorrei fare qualcosa di simile:

var switches = [true, true, false, true]; 

var holder = { 
    0: function() { /* do step0 */ } 
    1: function() { /* do step1 */ } 
    2: function() { /* do step2 */ } 
    3: function() { /* do step3 */ } 
    // ...etc... 
} 

for (var i = 0; i < switches.length; i++) 
    if (switches[i]) 
     holder[i](); 

C'è un modo per fare qualcosa di simile a questo in Python? L'unica cosa che mi viene in mente è qualcosa di simile:

switches = [True, True, False, True] 

class Holder(object): 
    @staticmethod 
    def do_0(): 
     # do step0 

    @staticmethod 
    def do_1(): 
     # do step 1 

    # ...etc... 

    def __repr__(self): 
     return [self.do_0, self.do_1, ...] 

for action in Holder: 
    action() 

Questo sembra solo terribilmente inefficiente se ho un numero significativo di passaggi. C'è un modo migliore per andare su questo?

+0

Un decoratore potrebbe essere più in linea con quello che desideri –

+0

Quale sarebbe il modo migliore per farlo? Se definisco tutte le funzioni con lo stesso decoratore, c'è un modo semplice per collegarsi tra loro senza creare una lista da scorrere? –

risposta

2

Si guarda come se non ci fosse un modo per farlo in Python, una decisione di design fatta intenzionalmente da quando è stata dichiarata non-Pythonic. Oh beh, sembra che io sia bloccato a definire i metodi e poi aggiungerli manualmente ad una lista per scorrere.

Fonte: https://softwareengineering.stackexchange.com/a/99245

3

È possibile farlo nel modo seguente:

# define your functions 
def fun1(): 
    print("fun1") 

def fun2(): 
    print("fun2") 

def fun3(): 
    print("fun3") 


switches = [True, False, True]; 

# put them in a list (list makes more sense than dict based on your example) 
func_list = [fun1, fun2, fun3] 

# iterate over switches and corresponding functions, and execute 
# functions when s is True  
for s,f in zip(switches, func_list): 
    if s: f() 

Questo è un modo solo. Ce ne sono molti altri per esempio. utilizzando lambda, dict come si voleva, ecc

Per utilizzare lambda se le funzioni sono solo una linea, si può fare:

func_list = [lambda: print("lambda1"), 
      lambda: print("lambda2"), 
      lambda: print("lambda1")] 
+1

Il tuo codice funziona sicuramente, ma sto cercando di evitare di definire un sacco di funzioni al di fuori dell'ambito del dizionario. Potrei semplicemente usare il codice che ho già altrimenti. Sfortunatamente il codice con cui sto lavorando è un po 'più complicato rispetto all'esempio, e non potrei davvero definire una serie di funzioni senza rendere rapidamente illeggibile il codice. –

+1

Ho aggiunto l'esempio lambdas. Ma non puoi mettere tutto in lambda's però. – Marcin

+2

Python non ha funzioni anonime come JS. Sì, ci sono ['' 'lambda'''] (https://docs.python.org/2/tutorial/controlflow.html#lambda-expressions) s, ma sono limitati a una singola espressione. – pzp

1
- Your functions don't need to be enveloped in a utility class. 
- I don not see how the two blocks of code differ in efficiency. 
- You can use enumerate and lambdas to simplify your code. 

codice semplificato

d = {0: lambda: 'Performing Step 0', 
    1: lambda: 'Performing Step 1', 
    2: lambda: 'Performing Step 2', 
    3: lambda: 'Performing Step 3', 
    4: lambda: 'Performing Step 4'} 

for index, switch in enumerate([1, 0, 1, 1, 0]): 
    if switch == 1: d[index]() 
+0

L'esempio che ho fornito è notevolmente semplificato. Nel mio esempio reale, la classe Holder è in realtà solo una classe helper per contenere tutte le impostazioni per il mio processore passo. All'inizio ho anche cercato di usare lambda, ma sembra che non possano essere troppo complicati (cioè non funzioneranno per 15 righe di codice). –

-1

Io di solito andare su questo come il seguente. Mi piace questo approccio, perché aggiunge un minimo di overhead di digitazione al codice, e se si scrive un metodo aggiuntivo in seguito, nulla deve essere modificato altrove nel file.

def steptest0(): 
    code 
def steptest1(): 
    code 
def steptest2(): 
    code 

... 

tests = filter(lambda x: x.startswith('steptest'), 
       dir()) 
for t in tests: eval(t + '()') 

Ogni metodo è già messo in un dizionario automaticamente in Python, e dir() ci consente di accedere a tale.

Disclaimer. Ci sono diversi campanelli d'allarme che iniziano a scoppiare nella testa del fanatico pedonale medio alla vista di "eval" e alcuni possono addirittura avere attacchi. Lasciate che si difendano dalla valutazione usando invece un meccanismo di riflessione (che potrebbe renderlo meno leggibile, ma comunque ne vale la pena, poiché non possono essere accusati di usare "eval").