2011-07-22 19 views
7

Używam Pythona na mój przykład, ale moje pytanie odnosi się ogólnie do języków programowania.Użycie zwrotu w długich instrukcjach if-elseif-else (Python)

def some_function(eggs): 
    if eggs == 1: 
     do_something_1() 
    elif eggs == 2: 
     do_something_2() 
    elif eggs == 3: 
     do_something_3() 
    else: 
     do_error() 
     return 
    do_something_4() 
    do_something_5() 
    do_something_6() 

(To jest tylko przykład. Moje funkcje nie będą nazywane do_something_x.)

Byłoby umieszczenie zwrotu w innego jak to być złe praktyki programowania? Czy lepszym rozwiązaniem byłoby umieszczenie w każdym elemencie if/elif pojedynczej jednostki?

Odpowiedz

11

Główny problem widzę w kodzie jest to, że w przypadku błędu jest ukryty więcej niż w połowie korpusu funkcji. To sprawia, że ​​kod jest trudny do odczytania. Ponieważ to, co robisz, polega na sprawdzaniu poprawności argumentów funkcji, powinieneś to zrobić w pierwszej kolejności.

Moja preferencja w przypadku nieprawidłowego argumentu polega na podniesieniu odpowiedniego wyjątku, takiego jak ValueError. Nie wiedząc, co robi twoja funkcja, ani co robi do_error, trudno powiedzieć z całkowitą pewnością, że dotyczy to twojego przypadku. Ale generalnie, pobieranie błędnych argumentów nie jest czymś, z czego można odzyskać funkcję. Dzwoniący podał argumenty; więc zrób to na dzwoniącym, aby odzyskać od tego błędu.

Również tutaj jest idiom można użyć, aby uniknąć długich list od elif s:

funs = {1: do_something_1, 
     2: do_something_2, 
     3: do_something_3} 
funs[eggs]() 
+3

Lub nawet 'funs.get (eggs, do_error)()', aby obsłużyć przypadek, w którym 'eggs' nie jest w' funs'. –

+0

Poprzez walidację argumentów, masz na myśli "jeśli jaja! = 1 i jaja! = 2 i jaja! = 3"? Ponieważ nie jest to bardzo proste, jeśli mam 100 opcji wartości jaj. –

+0

Jeśli użyjesz idiomu, który zasugerowałem, spójrz na komentarz Andrzeja lub użyj "jeśli jaja nie są w zabawach: podnieś ValueError (" Nieprawidłowa liczba jaj "). –

3

Jak o:

def some_function(eggs): 
    if eggs not in [1,2,3]: 
     do_error() 
     return 

    if eggs == 1: 
     do_something_1() 
    elif eggs == 2: 
     do_something_2() 
    elif eggs == 3: 
     do_something_3() 
    else: 
     assert False 
    do_something_4() 
    do_something_5() 
    do_something_6() 
+2

Ta odpowiedź naprawdę mi się podoba. Istnieją dwa obozy: wczesne powroty: "wszystkie funkcje powinny mieć jeden punkt wyjścia" oraz obóz "wrócić, kiedy możesz ograniczyć całkowite przetwarzanie". Mam tendencję do bocznego z tym ostatnim, zwłaszcza z python. Wydaje się upraszczać funkcje, zmniejszać wcięcia i "czuć" czystsze. –

+5

Nie jestem zbytnio zadowolony z asercji, ponieważ jest ona tutaj użyta, masz już niezmiennie zaznaczone bezpośrednio na górze. – SingleNegationElimination

+0

Problemem, który widzę z tym, jest fakt, że jest to faktycznie przykład powielania kodu - dokładny problem, którego chcemy uniknąć. Posiadanie opcji (1,2,3) wymienionych w wielu miejscach otwiera możliwość późniejszego błędnego dopasowania. Co się stanie, jeśli autor doda opcję 4, ale nie zaktualizuje "nie w"? – dhg

2

Czy jesteś pewien, że do_something_n jest bardzo podobne do do_something_m?

Jeśli tak, użyj do_something(var, n) i użyj tego samego kodu do wszystkiego z kilkoma znakami if (po tym wszystkim, że koncepcja jest naprawdę powiązana, prawda?).

Jeśli nie, podziel funkcje na naprawdę użyteczne i autonomiczne funkcje.


Przykład dlaczego to (prawdopodobnie) jest złe:

def print1(): 
    print(1) 

def print2(): 
    print(2) 

Cóż, każdy powinien zobaczyć ten powinien być printn(n) lub coś podobnego.

A druga prawdopodobieństwo:

def action1(): 
    paymanagers() 
    payworkers() 

def action2(): 
    clean_trashbin() 
    unlock_car() 

Działania te są prawdopodobnie związane i nie powinna należeć w swoich funkcjach.

1

To, co teraz robisz, nie jest złą praktyką programistyczną, ale niewłaściwym zwyczajem byłoby duplikowanie kodu poprzez umieszczenie trzech wywołań funkcji w każdym oświadczeniu if.

Niektórzy ludzie wolą mieć jeden punkt wyjścia do ich funkcji, w tym przypadku chciałbym zaproponować coś takiego:

def some_function(eggs): 
    error_code = 0 
    if eggs == 1: 
     do_something_1() 
    elif eggs == 2: 
     do_something_2() 
    elif eggs == 3: 
     do_something_3() 
    else: 
     do_error() 
     error_code = 1 

    if error_code == 0: 
     do_something_4() 
     do_something_5() 
     do_something_6() 
    return # return error_code if it would be helpful to the calling function 
+3

Osoby te powinny używać innego, bardziej funkcjonalnego języka, jeśli jest to dla nich ważne. Wracając wcześnie jest * znacznie * czystszy, bardziej czytelny i łatwiejszy w utrzymaniu niż przekrzywianie kodu za pomocą zmiennych 'error_code'. –

8

Zdecydowanie nie kopia identyczny kod do każdej klauzuli if.

Jak o:

def some_function(eggs): 
    options = {1: do_something_1, 2: do_something_2, 3: do_something_3} 
    if eggs in options: 
     options[eggs]() 
     do_something_4() 
     do_something_5() 
     do_something_6() 
    else: 
     do_error() 
     return 

nie wymagają długiego ifelifelse. Jest też jasne, że do_something_4() itd. Dzieje się tylko wtedy, gdy jaja to 1, 2 lub 3.

Powiązane problemy