Zanurkuj w Pythonie/Funkcja getattr
Funkcja getattr
[edytuj]Powinniśmy już wiedzieć, że w Pythonie funkcje są obiektami. Ponadto możemy dostać referencję do funkcji bez znajomości jej nazwy przed uruchomieniem programu. W tym celu podczas działania programu należy wykorzystać funkcję getattr.
getattr >>> li = ["Larry", "Curly"] >>> li.pop #(1) <built-in method pop of list object at 010DF884> >>> getattr(li, "pop") #(2) <built-in method pop of list object at 010DF884> >>> getattr(li, "append")("Moe") #(3) >>> li ["Larry", "Curly", "Moe"] >>> getattr({}, "clear") #(4) <built-in method clear of dictionary object at 00F113D4> >>> getattr((), "pop") #(5) Traceback (most recent call last): File "<stdin>", line 1, in ? AttributeError: 'tuple' object has no attribute 'pop'
- Dzięki temu dostaliśmy referencję do metody
pop. Zauważmy, że w ten sposób nie wywołujemy metodypop; aby ją wywołać musielibyśmy wpisać polecenieli.pop(). Otrzymujemy referencję do tej metody. (Adres szesnastkowy wygląda inaczej na różnych komputerach, dlatego wyjścia będą się nieco różnić.) - Operacja ta także zwróciła referencję do metody
pop, lecz tym razem nazwa metody jest określona poprzez łańcuch znaków w argumencie funkcjigetattr.getattrjest bardzo przydatną, wbudowaną funkcją, która zwraca pewien atrybut dowolnego obiektu. Tutaj wykorzystujemy obiekt, który jest listą, a atrybutem jest metodapop. - Dzięki temu przykładowi możemy zobaczyć, jaki duży potencjał kryje się w funkcji
getattr. W tym przypadku zwracaną wartościągetattrjest metoda (referencja do metody). Metodę tę możemy wykonać podobnie, jak byśmy bezpośrednio wywołalili.append("Moe"). Tym razem nie wywołujemy funkcji bezpośrednio, lecz określamy nazwę funkcji za pomocą łańcucha znaków. getattrbez problemu pracuje na słownikach- Teoretycznie
getattrpowinien pracować na krotkach, jednak krotki nie posiadają żadnej metody, dlategogetattrspowoduje wystąpienie wyjątku związanego z brakiem atrybutu o podanej nazwie.
getattr na modułach
[edytuj]getattr działa nie tylko na wbudowanych typach danych. Argumentem tej funkcji może być także moduł.
getattr w apihelper.py >>> import odbchelper >>> odbchelper.buildConnectionString #(1) <function buildConnectionString at 00D18DD4> >>> getattr(odbchelper, "buildConnectionString") #(2) <function buildConnectionString at 00D18DD4> >>> object = odbchelper >>> method = "buildConnectionString" >>> getattr(object, method) #(3) <function buildConnectionString at 00D18DD4> >>> type(getattr(object, method)) #(4) <type 'function'> >>> import types >>> type(getattr(object, method)) == types.FunctionType True >>> callable(getattr(object, method)) #(5) True
- Polecenie to zwraca nam referencję do funkcji
buildConnectionStringz modułuodbchelper, który przeanalizowaliśmy w Rozdziale 2. - Wykorzystując
getattr, możemy dostać taką samą referencję, do tej samej funkcji. W ogólnościgetattr(obiekt, "atrybut")jest odpowiednikiemobiekt.atrybut. Jeśli obiekt jest modułem, atrybutem może być cokolwiek zdefiniowane w tym module np. funkcja, klasa czy zmienna globalna. - Tę możliwość wykorzystaliśmy w funkcji
info. Obiekt o nazwieobjectzostał przekazany jako argument do funkcjigetattr, ponadto przekazaliśmy nazwę pewnej metody lub funkcji jako zmiennąmethod. - W tym przypadku zmienna
methodprzechowuje nazwę funkcji, co można sprawdzić pobierając typ zwracanej wartości. - Ponieważ zmienna
methodjest funkcją, więc można ją wywoływać. Zatem w wyniku wywołaniacallableotrzymaliśmy wartośćTrue.
getattr jako funkcja pośrednicząca
[edytuj]Funkcja getattr jest powszechnie używana jako funkcja pośrednicząca (ang. dispatcher). Na przykład mamy napisany program, który może wypisywać dane w różnych formatach (np. HTML i PS). Wówczas dla każdego formatu wyjścia możemy zdefiniować odpowiednią funkcję, a podczas wypisywania danych na wyjście getattr będzie nam pośredniczył między tymi funkcjami. Jeśli wydaje się to trochę zagmatwane, zaraz zobaczymy przykład.
Wyobraźmy sobie program, który potrafi wyświetlać statystyki strony w formacie HTML, XML i w czystym tekście. Wybór właściwego formatu może być określony w linii poleceń lub przechowywany w pliku konfiguracyjnym. Moduł statsout definiuje trzy funkcje -- output_html, output_xml i output_text, a wówczas program główny może zdefiniować pojedynczą funkcję, która wypisuje dane na wyjście:
getattr import statsout def output(data, format="text"): #(1) output_function = getattr(statsout, "output_%s" % format) #(2) return output_function(data) #(3) - Funkcja
outputwymaga jednego argumentu o nazwiedata, który ma zawierać dane do wypisania na wyjście. Funkcja ta może także przyjąć jeden opcjonalny argumentformat, który określa format wyjścia. Gdy argumentformatnie zostanie określony, przyjmie on wartość"text", a funkcja się zakończy wywołując funkcjęoutput_text, która wypisuje dane na wyjście w postaci czystego tekstu. - Łańcuch znaków
"output_"połączyliśmy z argumentemformat, aby otrzymać nazwę funkcji. Następnie pobraliśmy funkcję o tej nazwie z modułustatsout. Dzięki temu w przyszłości będzie łatwiej rozszerzyć program nie zmieniając funkcji pośredniczącej, aby obsługiwał więcej wyjściowych formatów. W tym celu wystarczy dodać odpowiednią funkcję dostatsoutnp.output_pdfi wywołujemy funkcjęoutputpodając argumentformatjako"pdf". - Teraz możemy wywołać funkcję wyjściową w taki sam sposób jak inne funkcje. Zmienna
output_functionjest referencją do odpowiedniej funkcji wstatsout.
Czy znaleźliśmy błąd w poprzednim przykładzie? Jest to bardzo niestabilne rozwiązanie, ponadto nie ma tu kontroli błędów. Co się stanie gdy użytkownik poda format, którego nie zdefiniowaliśmy w statsout? Funkcja getattr rzuci nam wyjątek związany z błędnym argumentem, czyli podaną nazwą funkcji, która nie istnieje w module statsout.
Na szczęście do funkcji getattr możemy podać trzeci, opcjonalny argument, czyli domyślnie zwracaną wartość, gdy podany atrybut nie istnieje.
getattr import statsout def output(data, format="text"): output_function = getattr(statsout, "output_%s" % format, statsout.output_text) return output_function(data) #(1) - Ta funkcja już na pewno będzie działała poprawnie, ponieważ podaliśmy trzeci argument w wywołaniu funkcji
getattr. Trzeci argument jest domyślną wartością, która zostanie zwrócona, gdy podany atrybut, czy metoda nie zostanie znaleziona.
Jak mogliśmy zauważyć, funkcja getattr jest niezwykle użyteczna. Jest ona sercem introspekcji. W następnych rozdziałach zobaczymy jeszcze więcej przydatnych przykładów.