Forum >> Principianti >> troppi if state

Pagina: 1

ciao a tutti,

il mio problema è relativo ad una funzione che deve cambiare il suo comportamento a seconda di 3 parametri di input (mettiamo a,b,c). I parametri possono essere None o non None, e ad ogni combinazione di questi 3 parametri è associato un comportamento differente della funzione.

Conoscete un modo di avere questo effetto senza usare quella enorme file di costrutti if elif else? leggevo di un design pattern chiamato state ma so se può fare al caso mio.


grazie a tutti in anticipo! :hug-right:

Mah, 8 combinazioni diverse sono una roba da dizionario, nella peggiore delle ipotesi. Avessi detto 80 combinazioni, 800 combinazioni...


A parte che quello che descrivi non sembra affatto UNA funzione, ma una switchboard per 8 funzioni diverse. Ma saprai tu.


Poi a seconda di quello che stai davvero cercando di fare, magari un po' di razionalizzazione e riflessione con carta-e-penna ti portano a cose più eleganti... Per dire, io vedo sempre un po' con sospetto il pattern "una funzione che se c'è il parametro fa una cosa, e se il parametro è None fa tutt'altra cosa". Allora sono due funzioni, non una - e stai semplicemente ficcando a martellate la validazione dell'input dentro la funzione. Allora perché non scrivere qualcosa come:


def risolutore_universale_dei_problemi_del_mondo(x):
    if x is None: ....
    elif x == 42: .....
    elif x == 'hello': .....
    elif x % 15 == 3: .....
    ....
Però ripeto, saprai tu. Nella peggiore delle ipotesi, 8 combinazioni sono comunque un dictionary dispatching.





(Uhm, scusa, ma devo proprio dirlo: da quel poco che ricordo dei tuoi post, mi sembra che tu abbia *davvero* il gusto di complicarti la vita. Ehm, e di citare nomi di oop pattern random... Sbaglierò...)

ciao RicPol ! in realtà ti leggo sempre con molto interesse e ho seguito quasi nella totalità quello che mi hai consigliato quindi sono contento che mi hai risposto :D.

Sul pattern state era uscito dopo qualche ricerca online dove qualcuno lo consigliava per strutturare casi in cui ci fossero differenti switch ma non avendo capito il nesso (non avendo mai nemmeno avuto occasione di utilizzarlo..) ho chiesto.

Al momento stavo operando con un dizionario che presentava come chiavi delle tuple di lunghezza 3 (es. (None,None,None)) e come valori delle funzioni specifiche (come una sorta di tabella di switch non saprei come chiamarla)... ma come dici tu sicuramente mi sto complicando la vita e non vedo un modo più semplice.

Quello che vorrei ottenere è una funzione relativamente elastica che si comporta in modo differente a seconda degli input. Ti allego un esempio per capirci:

def func(l: list, a=None, b=None, c=None):
    if a is None and b is None and c is None:
        a = 0.
        c = 1.
        b = a + (len(l) -1)*c
    elif a is not None and b is None and c is None:
        c = 1.
        b = a + (len(l) -1)*c
    elif a is None and b is not None and c is None:
        c = 1.
        a = b - (len(l) -1)*c
    elif a is None and b is None and c is not None:
        a = 0.
        b = a + (len(l) -1)*c 
   
    (. . .)
    
    return a,b,c
la def così è totalmente inutile ma il concetto è il medesimo, in sostanza c'è un legame tra le 3 variabili a,b,c ovvero sono legate dalla lunghezza della lista in ingresso, ma non riesco a trovare uno modo per metterlo giù in modo più compatto.




Mah guarda, stai veramente facendo un'insalata russa di concetti. Tra l'altro, non è per esplicitare l'ovvio ma insomma, una *funzione* è per definizione "stateless", al contrario di un *oggetto* che rispetto a una funzione ha appunto la virtù di mantenere uno stato. E "state" è un OOP pattern, dove appunto la prima O di OOP sta per "object", "oggetto". Oggetto, non funzione, capisci. Oggetto. Non funzione. Oggetto.


Ora, poi certamente si può ragionare di pattern OOP come se fossero delle metafore, e applicarli in qualche modo alle funzioni, o anche alle ricette per la pastasciutta se vuoi. Dopo tutto i pattern OOP hanno un po' questa caratteristica di essere astratti, di spostare l'attenzione sulla riflessione generale... un po' delle lezioni di vita, se vuoi. Quindi non metto in dubbio che si possa ragionare di pattern "state" anche quando in mano hai solo delle funzioni. Ma francamente, prima bisognerebbe sapere di cosa si sta parlando.


Se il tuo interesse è nei pattern OOP, ti faccio una proposta pazzesca: che ne dici di leggerti un libro sui pattern OOP per scoprire che cosa sono? Potresti essere a un passo da molte fantastiche scoperte.





Per quanto riguarda quella funzione, non so proprio che dire. E' una filastrocca assurda, e proprio non ho idea di quale potrebbe essere il caso concreto in cui non c'è *nessun'altra* soluzione se non usare una roba del genere. A me sembra che, *se* davvero non si riesce a impostare il problema in modo più semplice (ma davvero, davvero davvero, non posso crederci che non ci si riesca), *allora* una sequenza di if-elif sia ancora la cosa migliore da fare: è semplice, magari un po' prolissa ma chiara.


Poi certo, anche solo vedendo quel poco di codice che hai scritto, saltano agli occhi delle cose... per esempio, se "c" non è None allora è "1". Ma questo non è un banale argomento di default? "a" OPPURE "b" sono sempre uguali a "(len(l)-1)*c"... uhm, questo puzza parecchio: non sarà meglio dire che da un lato esiste "(len(c)-1)*c" che serve sempre, dall'altro eliminare "a" oppure "b" completamente e riservare un solo argomento per questo? Eccetera. Boh, ovviamente dipende da quello che stai cercando di fare davvero, ma insomma...


E in ogni caso sono convinto che con un po' di ragionamento carta-e-penna si riesce a impostare il problema in modo più semplice.





A monte di tutto questo, tieni presente che quello che stai cercando di fare ("una funzione relativamente elastica che si comporta in modo differente a seconda degli input") è un noto anti-pattern. Una funzione racchiude UN algoritmo che lavora a partire da diversi input che però non modificano l'algoritmo. Se la tua funzione contiene più algoritmi che vengono decisi a runtime a seconda del valore dei parametri in input, allora quella non dovrebbe essere una funzione, ma tante funzioni separate.


Quello che stai facendo è una cosa simile ai parametri-flag. Googla per "flag argument code smell", "flag argument antipattern", eccetera. E ovviamente, per buona misura, googla per "single reponsibility principle".





Pagina: 1



Esegui il login per scrivere una risposta.