2011-10-22 10 views
6

Mam sytuację, w której mam sześć możliwych sytuacji, które mogą odnosić się do czterech różnych wyników. Zamiast używać rozszerzonej instrukcji if/else, zastanawiałem się, czy byłoby bardziej pythonic używać słownika do wywoływania funkcji, które nazwałbym wewnątrz instrukcji if/else jako zamiennika dla instrukcji "switch", jak można by użyć w języku C# lub php.Czy jest to "pythonic" metoda wykonywania funkcji jako instrukcja przełączania Pythona dla wartości krotki?

Moja instrukcja switch zależy od dwóch wartości, których używam do zbudowania krotki, którą z kolei użyję jako klucz do słownika, który będzie funkcjonował jako mój "przełącznik". Będę pobierał wartości dla krotki z dwóch innych funkcji (wywołania bazy danych), dlatego mam przykład funkcji jeden() i zero().

Jest to wzór kod mam na myśli używając który natknąłem się na z zabawy w łupinach Pythona:

def one(): 
    #Simulated database value 
    return 1 

def zero(): 
    return 0 

def run(): 
    #Shows the correct function ran 
    print "RUN" 
    return 1 

def walk(): 
    print "WALK" 
    return 1 

def main(): 
    switch_dictionary = {} 

    #These are the values that I will want to use to decide 
    #which functions to use 
    switch_dictionary[(0,0)] = run 
    switch_dictionary[(1,1)] = walk 

    #These are the tuples that I will build from the database 
    zero_tuple = (zero(), zero()) 
    one_tuple = (one(), one()) 

    #These actually run the functions. In practice I will simply 
    #have the one tuple which is dependent on the database information 
    #to run the function that I defined before 
    switch_dictionary[zero_tuple]() 
    switch_dictionary[one_tuple]() 

nie mam rzeczywisty kod napisany albo będę po to tutaj, jako Chciałbym wiedzieć, czy ta metoda jest uważana za najlepszą praktykę Pythona. Nadal jestem uczniem Pythona na uniwersytecie i jeśli jest to metoda, która jest złym nawykiem, to chciałbym ją teraz wyrzucić, zanim wyjdę na prawdziwy świat.

Uwaga, wynik wykonania powyższego kodu jest zgodny z oczekiwaniami, po prostu "RUN" i "WALK".

edit

Dla tych z Was, którzy są zainteresowani, to w jaki sposób odpowiedni kod okazało. Jest używany w aplikacji do obsługi aplikacji Google. Powinieneś odkryć, że kod jest znacznie bardziej uporządkowany niż mój przykładowy wzór. Działa znacznie lepiej niż moje wcześniejsze zawiłe drzewo if/else.

def GetAssignedAgent(self): 
    tPaypal = PaypalOrder() #Parent class for this function 
    tAgents = [] 
    Switch = {} 

    #These are the different methods for the actions to take 
    Switch[(0,0)] = tPaypal.AssignNoAgent 
    Switch[(0,1)] = tPaypal.UseBackupAgents 
    Switch[(0,2)] = tPaypal.UseBackupAgents 
    Switch[(1,0)] = tPaypal.UseFullAgents 
    Switch[(1,1)] = tPaypal.UseFullAndBackupAgents 
    Switch[(1,2)] = tPaypal.UseFullAndBackupAgents 
    Switch[(2,0)] = tPaypal.UseFullAgents 
    Switch[(2,1)] = tPaypal.UseFullAgents 
    Switch[(2,2)] = tPaypal.UseFullAgents 

    #I'm only interested in the number up to 2, which is why 
    #I can consider the Switch dictionary to be all options available. 
    #The "state" is the current status of the customer agent system 
    tCurrentState = (tPaypal.GetNumberofAvailableAgents(), 
        tPaypal.GetNumberofBackupAgents()) 

    tAgents = Switch[tCurrentState]() 
+0

Znacznie lepiej! Bardzo czytelny i "Pythoniczny" – dawg

+0

Zauważ, że 'Przełącz [(x, y)]' może być napisany bardziej czysto jako 'Przełącz [x, y]' – Eric

Odpowiedz

11

Rozważmy ten idiom Zamiast:

>>> def run(): 
... print 'run' 
... 
>>> def walk(): 
... print 'walk' 
... 
>>> def talk(): 
... print 'talk' 
>>> switch={'run':run,'walk':walk,'talk':talk} 
>>> switch['run']() 
run 

myślę, że jest trochę bardziej czytelne niż w kierunku, w którym zmierza.

edit

I to działa tak samo:

>>> switch={0:run,1:walk} 
>>> switch[0]() 
run 
>>> switch[max(0,1)]() 
walk 

Można nawet użyć tego idiomu o strukturze switch/default typu:

>>> default_value=1 
>>> try: 
... switch[49]() 
... except KeyError: 
... switch[default_value]() 

lub (mniej czytelny, bardziej zwięzły):

>>> switch[switch.get(49,default_value)]() 
walk 

edit 2

samo idiom, rozszerzone na swój komentarz:

>>> def get_t1(): 
... return 0 
... 
>>> def get_t2(): 
... return 1 
... 
>>> switch={(get_t1(),get_t2()):run} 
>>> switch 
{(0, 1): <function run at 0x100492d70>} 

Czytelność liczy

+0

Problem polega na tym, że będę dynamicznie konstruować krotkę w oparciu o wywołania bazy danych, ponieważ "już pracuję nad odejściem 0, 1 lub 2 w oparciu o bazę danych w wyniku funkcji. Zatem używanie krotek w stosunku do pojedynczych ciągów jest bardzo potrzebne, ponieważ potrzebuję użyć dwóch (potencjalnie więcej w przyszłości) wartości. Bardzo podoba mi się pomysł użycia "switch" jako nazwy słownika. –

+0

Możesz więc rozważyć skonstruowanie prostej klasy. Ogólnie rzecz biorąc "Pythonic" jest pamiętać, że czytelność ma duże znaczenie. Coś takiego jak 'switch_dictionary [(0,0)] = run' i' zero_tuple = (zero(), zero()) 'jest trudne dla innych (lub siebie po kilku miesiącach) do rozszyfrowania. Python ma tendencję do bycia bardzo czytelnym. Wybierane przez ciebie idiomy coś zmieniają. Możesz napisać ten sam kod w bardziej czytelny sposób. – dawg

+0

Mój szczególny problem jest podobny do systemu obsługi klienta, w którym przypisuje żądania klientów dwóm różnym rodzajom agentów obsługi klienta (każda połowa krotki w moim opisie), ale zmienia swoje zachowanie w zależności od liczby każdego rodzaju agenta online. Krotka będzie coś w stylu (GetTier1(), GetTier2()), więc prawdopodobnie krotka w tym przypadku jest najbardziej czytelna? Nie jestem przyzwyczajony do czytania kodu Pythona, więc jestem naprawdę zainteresowany. –

2

Jest to dość powszechna praktyka pyton wysyłką do funkcji na podstawie słownika lub sekwencji lookup.

Biorąc pod uwagę korzystanie z indeksów dla odnośnika, lista list będzie również pracować:

switch_list = [[run, None], [None, walk]] 
    ... 
switch_list[zero_tuple]() 

Co jest uważane za najbardziej pythonowy jest ta, która maksymalizuje jasność przy jednoczesnym spełnieniu innych wymogów operacyjnych. W twoim przykładzie krotka wyszukiwania nie wydaje się mieć znaczenia wewnętrznego, więc intencja operacyjna jest tracona z magicznej stałej. Postaraj się, aby logika biznesowa nie zaginęła w twoim mechanizmie wysyłki. Używanie znaczących nazw stałych mogłoby pomóc.

Powiązane problemy