W zeszłym tygodniu pokazałem Ci w jaki sposób możesz uprościć swój kod. Wiesz już, że zamiast tworzyć duże konstrukcje warunkowe możesz generować nazwę wywoływanej metody “w locie” wykorzystując do tego zmienne. W tym tygodniu kontynuujemy ten temat. Pokażę Ci jak wykorzystać takie dynamicznie generowane odwołanie wraz z własnym słownikiem funkcji do wywołania.
Gdy dopuszczalnych wartości zmiennej jest zbyt wiele
Przykład z zeszłego tygodnia jest bardzo wygodny, jeżeli pojedyncza wartość zmiennej ma uruchamiać jedną dedykowaną metodę. Często jednak jest tak, że wskazana metoda może być uruchamiana dla wielu dozwolonych wartości zmiennej.
def method_A(x, y): print(x+y) def method_B(x, y): print(x+y+1) def method_C(x, y): print(x+y+2) i = 'C' globals()['method_' + i](1, 2)
Przyjmijmy, że funkcja method_A()
ma być uruchamiana zarówno dla wartości zmiennej 'A'
jak i 'AA'
. Funkcja method_B()
będzie wywoływana dla wartości 'B'
oraz 'BB'
i analogicznie dla trzeciej funkcji. W takim wypadku rozwiązanie z poprzedniego się nie sprawdzi, gdyż dla i = 'AA'
będziemy próbowali wywołać metodę method_AA()
, a taka nie istnieje.
Słownik z funkcjami do wywołania
Istnieją co najmnie dwa sposoby rozwiązania tego problemu. Po pierwsze możemy stworzyć konstrukcję warunkową. Za jej pomocą, wedle przyjętych kryteriów, zmodyfikujemy wartość zmiennej i
, by ostatecznie miała przypisany jedną z trzech wartości zgodnie z nazwami naszych funkcji. Jednak nie po to chcieliśmy uniknąć konstrukcji warunkowych, by teraz do nich powracać. Jaki jest zatem ten drugi sposób?
F = { 'A': method_A, 'B': method_B, 'C': method_C, 'AA': method_A, 'BB': method_B, 'CC': method_C } i = 'B' F[i](1, 2) i = 'CC' F[i](1, 2)
Jest on bardzo prosty – tworzymy nową zmienną typu dictionary, w której jako klucze podajemy dopuszczalne wartości zmiennej, a jako wartości nazwy funkcji do wywołania. Będzie ona słownikiem z funkcjami do wywołania w zależności od wartości klucza każdego z rekordów. Podobnie jak w poprzednim przykładzie wywołujemy funkcję, odwołując się do klucza w słowniku, a nie bezpośrednio do nazwy tej funkcji.
Przykład z mojego projektu
Można oczywiście dyskutować, czy jest to prostsze niż konstrukcje warunkowe, czy nie jest. Dużo zależeć będzie tu od indywidualnych preferencji programisty. Ja preferuję metodę ze słownikiem, gdyż wydaje się mi ona bardziej przejrzysta i łatwiejsza w zarządzaniu niż rozbudowana struktura if-elif
. Takie rozwiązanie zastosowałem też w moim projekcie CMLNetKit.
W moim programie muszę wywołać inną funkcję modyfikującą konfigurację startową urządzenia w zależności od jego typu. Typ każdego urządzenia odczytywany jest z konfiguracji topologii laba i zapisywany w zmiennej. Dla wielu typów urządzeń muszę wywołać tą samą metodę, gdyż przykładowo nazewnictwo interfejsów będzie identyczne. Potrzebowałem też zaadresować sytuację, w której dla danego typu urządzenia nie mam przygotowanej jeszcze odpowiedniej metody. W tym celu skorzystałem właśnie z przedstawionej powyżej metody tworząc słownik z funkcjami do wywołania. Kliknij w LINK aby zobaczyć jak to wygląda bezpośrednio na moim repozytorium.