Dekoratora używa się wstawiając linijkę zaczynającą się przed definicją dekorowanego obiektu (klasy czy funkcji).

Podobne dokumenty
Spis treści. Dekoratory. 1 Dekoratory 1.1 Zadanie Zadanie Zadanie Zadanie 4

Programowanie obiektowe

Programowanie i projektowanie obiektowe

Programowanie i projektowanie obiektowe

Programowanie i projektowanie obiektowe

Spis treści. Funkcje. 1 Funkcje 1.1 Zadanie Zadanie Zadanie Zadanie Zadanie Zadanie Zadanie 7

Podstawy Programowania Obiektowego

PHP 5 język obiektowy

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Wykład 5: Klasy cz. 3

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

Część XVII C++ Funkcje. Funkcja bezargumentowa Najprostszym przypadkiem funkcji jest jej wersja bezargumentowa. Spójrzmy na przykład.

Kurs rozszerzony języka Python

10. Programowanie obiektowe w PHP5

Obiektowy PHP. Czym jest obiekt? Definicja klasy. Składowe klasy pola i metody

PARADYGMATY PROGRAMOWANIA Wykład 4

Programowanie i projektowanie obiektowe

Programowanie obiektowe - 1.

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

C++ Przeładowanie operatorów i wzorce w klasach

Przykład 1: Funkcja jest obiektem, przypisanie funkcji o nazwie function() do zmiennej o nazwie funkcja1

Rozdział 4 KLASY, OBIEKTY, METODY

7. Pętle for. Przykłady

Programowanie obiektowe

Programowanie i projektowanie obiektowe

Wykład 3 Składnia języka C# (cz. 2)

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego. Iwona Kochaoska

Klasy abstrakcyjne i interfejsy

Słowa kluczowe jak góry lodowe

Programowanie obiektowe

Metaprogramowanie w Ruby

W dowolnym momencie można zmienić typ wskaźnika.

PROE wykład 3 klasa string, przeciążanie funkcji, operatory. dr inż. Jacek Naruniec

Wykład 8: klasy cz. 4

1 Wskaźniki. 1.1 Główne zastosowania wskaźników

Listy, krotki, słowniki, funkcje

Laboratorium 7 Blog: dodawanie i edycja wpisów

Funkcje są prawdopodobnie najważniejszą częścią każdego poważnego programu (w każdym języku programowania).

Python wstęp. Michał Bereta

Zadanie 2: Arytmetyka symboli

IX. Wskaźniki.(3 godz.)

Systemy operacyjne. Laboratorium 9. Perl wyrażenia regularne. Jarosław Rudy Politechnika Wrocławska 28 lutego 2017

4. Funkcje. Przykłady

Programowanie obiektowe

TECHNOLOGIE INTERNETOWE WYKŁAD 6. JavaScript Funkcje i obiekty

TEMAT : KLASY DZIEDZICZENIE

Technologie i usługi internetowe cz. 2

Backend Administratora

Czym są właściwości. Poprawne projektowanie klas

Wzorce projektowe. dr inż. Marcin Pietroo

Uniwersytet Zielonogórski Instytut Sterowania i Systemów Informatycznych. Ćwiczenie 3 stos Laboratorium Metod i Języków Programowania

Plan. krótkie opisy modułów. 1 Uwagi na temat wydajności CPython a. 2 Podstawowe techniki poprawiające wydajność obliczeniową

Zaawansowany kurs języka Python

Szablony funkcji i szablony klas

Wykład 4 Delegat (delegate), właściwości indeksowane, zdarzenie (event) Zofia Kruczkiewicz

Common Lisp - funkcje i zmienne

Informatyka I. Dziedziczenie. Nadpisanie metod. Klasy abstrakcyjne. Wskaźnik this. Metody i pola statyczne. dr inż. Andrzej Czerepicki

xmlns:prism= c. <ContentControl prism:regionmanager.regionname="mainregion" />

Kurs języka Python. Wykład 11. Marcin Młotkowski. 4 stycznia Kontrola poprawności podczas biegu programu. 2 Testowanie oprogramowania

Podstawy i języki programowania

Podstawy informatyki. Elektrotechnika I rok. Język C++ Operacje na danych - wskaźniki Instrukcja do ćwiczenia

Klasy Obiekty Dziedziczenie i zaawansowane cechy Objective-C

Paradygmaty programowania

Wstęp do programowania

Instytut Mechaniki i Inżynierii Obliczeniowej Wydział Mechaniczny Technologiczny Politechnika Śląska

10 Płatności [ Płatności ] 69

Programowanie komputerowe. Zajęcia 7

Ćwiczenie 5. Python 3: Programowanie obiektowe i dziedziczenie

PHP: bloki kodu, tablice, obiekty i formularze

Typy, klasy typów, składnie w funkcji

Programowanie obiektowe

ZASADY PROGRAMOWANIA KOMPUTERÓW

.NET Klasy, obiekty. ciąg dalszy

C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów

Przeciążanie operatorów

Szablony funkcji i klas (templates)

Wskaźniki w C. Anna Gogolińska

Kumulowanie się defektów jest możliwe - analiza i potwierdzenie tezy

Kurs programowania. Wstęp - wykład 0. Wojciech Macyna. 22 lutego 2016

Swift (pol. jerzyk) nowy język programowania zaprezentowany latem 2014 r. (prace od 2010 r.)

Podczas dziedziczenia obiekt klasy pochodnej może być wskazywany przez wskaźnik typu klasy bazowej.

Typy klasowe (klasy) 1. Programowanie obiektowe. 2. Założenia paradygmatu obiektowego:

Java pierwszy program w Eclipse «Grzegorz Góralski strona własna

Programowanie w Javie 1 Wykład i Ćwiczenia 3 Programowanie obiektowe w Javie cd. Płock, 16 października 2013 r.

Programowanie i projektowanie obiektowe

Kurs WWW. Paweł Rajba.

Szablony klas, zastosowanie szablonów w programach

Wzorce Strukturalne. Adapter: opis. Tomasz Borzyszkowski

Podstawy Języka Java

Delphi podstawy programowania. Środowisko Delphi

private - oznacza, że wszystkie elementy klasy bazowej zmieniają się w prywatne.

Zajęcia 4 - Wprowadzenie do Javascript

Sphinx - system dokumentacji dla Pythona

PROE wykład 2 operacje na wskaźnikach. dr inż. Jacek Naruniec

Paweł Kurzawa, Delfina Kongo

Modele danych walidacja widoki zorientowane na model

Transkrypt:

Dekoratory są w miarę ezoteryczną cechą Pythona w przeciwieństwie do funkcji, klas czy iteratorów nie są powszechną cechą języków programowania. Niemniej, warto je omówić mimo wszystko, gdyż są niezwykle eleganckie i użyteczne. Krótko mówiąc, dekorator to obiekt (np. funkcja), który można wywołać przekazując mu jako argument dekorowany obiekt. Tym dekorowanym obiektem może być funkcja lub klasa. Wartość zwrócona przez to wywołanie zostaje użyta zamiast dekorowanego obiektu. Spis treści 1 Składnia 2 Klasyczne zastosowanie dekoratorów: metody statyczne i klasowe 3 Dekoratory definiowane jako funkcje czy klasy 4 Dekorator typu trace 5 Dekoratora zwracające oryginalną funkcję i dekoratory zwracające inny obiekt 6 Do czego (i czy wogóle) warto używać dekoratorów? 7 Przydatne linki Składnia Dekoratora używa się wstawiając linijkę zaczynającą się od @ przed definicją dekorowanego obiektu (klasy czy funkcji). Popatrzmy na przykład: >>> def ustaw_atrybut_xxx(funkcja): # definicja naszego dekoratora... funkcja.xxx = True... return funkcja >>> @ustaw_atrybut_xxx # wywołanie dekoratora... def f(): # dekorowany obiekt... print "ciao" >>> f() # wywołanie obiektu zwróconego przez dekorator ciao >>> f.xxx # dodatkowy atrybut ustawiony przez dekorator True Definicja funkcji (zaczynająca się od def) tworzy funkcję, czyli obiekt typu function). Ten obiekt jest przepuszczany przez funkcję ustaw_atrybut_xxx, która dodaje dodatkowe pole. W rezultacie zastosowanie dekoratora powoduje, że pod nazwą f zostaje zachowana oryginalna funkcja, ale z dodatkowym atrybutem.

Składnia wywołania dekoratorów jest pomyślana tak, by trudno było przeoczyć fakt, że definiowany obiekt został dekorowany. Niemniej, zanim pojawiła się składnia z @, możliwe było użycie dekoratorów poprzez jawne wywołanie: >>> def f():... print "ciao" >>> f = ustaw_atrybut_xxx(f) # równoważne użyciu @ustaw_atrybut_xxx w poprzednim przykładzie >>> f() ciao >>> f.xxx True Ten przykład pokazuje też, co dokładnie powoduje wstawienie dekoratora zachowanie pod nazwą definiowanej funkcji wartości zwracanej przez wywołanie dekoratora z oryginalną funkcja jako argumentem. Klasyczne zastosowanie dekoratorów: metody statyczne i klasowe Funkcje zdefiniowane w klasie tworzą metody. Ich pierwszy argument to zawsze self, magiczny parametr za który Python podstawia obiekt na którym wywoływana jest metoda. Niemniej, czasami wygodnie jest zdefiniować w klasie funkcję, którą można wywołać bez dostępu do instancji. Aby mieć taką możliwość, definiuje się metodę klasową (używając dekoratora classmethod) lub statyczną (używając dekoratora staticmethod). Różnica między nimi jest taka, że metoda klasowa ma pierwszy magiczny parametr tak samo jak zwykłe metody, tylko że Python wstawia za niego samą klasę, a nie jedną z jej instancji. Metoda statyczna zachowuje się jak zwykła funkcja, i lista argumentów jest przekazywana bez zmian. >>> class T(object):... def a(self, x):... print self, x...... @classmethod... def b(cls, x):... print cls, x...... @staticmethod:... def c(x):... print x >>> t = T() >>> t.a(1) < main.t object at...> 1 >>> t.b(2)

<class ' main.test'> 2 >>> t.c(3) 3 >>> # nie możemy wywołać T.a() >>> T.b(4) <class ' main.test'> 4 >>> T.c(5) 5 Istotna różnica między metodą a i metodami b oraz c jest to, że te drugie można wywołać poprzez klasę, bez tworzenia instancji. Nazwy pierwszego parametru metod a i b, czyli self i cls powinny być właśnie takie. Użycie nazwy self dla parametru nie będącego pierwszym parametrem zwykłej metody prowadzi do konfuzji osoby czytającej kod. Podobnie nazwanie takiego parametru jakkolwiek inaczej jest złamaniem reguł stylu. W przypadku parametru cls reguły nie są aż takie ścisłe, gdyż czasem nazywa się go klass, niemniej użycie słowa nie kojarzącego się od razu z klasą jest również błędem. Dekoratory definiowane jako funkcje czy klasy Zdefiniowany na początku dekorator ustaw_atrybut_xxx, mimo że wystarczający do zademonstrowania składni, raczej nie nie ma zastosowania praktycznego. Zanim przejdziemy do definiowania użytecznych dekoratorów, omówmy w jaki sposób można to zrobić. Na wstępnie zaznaczyliśmy, że dekorator to obiekt który można wywołać jak funkcję. Jako funkcja był też napisany nasz przykładowy dekorator ustaw_atrybut_xxx. Inny sposób na otrzymanie wywoływalnych obiektów to zdefiniowanie klasy z metodą call. Przewaga klasowego podejścia do dekoratorów nad funkcyjnym jest taka, że są one w ten sposób czytelniejsze. Definiowanie dekoratorów przy użyciu funkcji wymaga zastosowania dwu- lub trzykrotnie zagnieżdzonych funkcji. Przy definicji przez klasę analogiczna definicja zawiera po prostu dwie lub trzy metody. Dlatego też, w niniejszym omówieniu, dalsze dekoratory będziemy definiować jako klasy. Na początek przypomnijmy, jak działa dodanie specjalnej metody call. Mianowicie, jeśli mamy obiekt, którego klasa definiuje call, to można go użyć jak funkcji i wywoła (dostawiając listę argumentów w nawiasach okrągłych). >>> class T(object):... def init (self):... print "w init "... def call (self):... print "w call " >>> t = T() w init >>> t() w call

Przypomnijmy też, jak działa dodanie metody init. Mianowicie, zostaje ona wywołana automatycznie po tym, jak stworzymy nowy obiekt. Tworzenie obiektów w Pythonie przypomina zwykłe wywołanie funkcji, tyle tylko, że zamiast funkcji używa się klasy. Metoda init nie zwraca nic. Reasumując, operacja wywołania dokonana na klasie powoduje stworzenie nowego obiektu i wywołanie init, natomiast operacja wywołania dokonana na obiekcie powoduje wywołanie call. Dla przykładu zdefiniujmy ustaw_atrybut_xxx na nowo, tym razem jako klasę. >>> class ustaw_atrybut_xxx(object):... def init (self):... pass... def call (self, funkcja):... funkcja.xxx = True... return funkcja >>> @ustaw_atrybut_xxx()... def f():... return 'bonjour' >>> f() 'bonjour' >>> f.xxx True Nieco inny jest sposób wykorzystania dekoratora o ile wcześniej po znaku @ następowała tylko nazwa funkcji, to teraz dostawiliśmy nawiasy, tak by skonstruować obiekt ustaw_atrybut_xxx.o Dekorator typu trace Zdefiniujmy użyteczny dekorator, który wypisze nazwę wykonywanej funkcji przed i po jej wykonaniu. >>> class logged(object):... def init (self, funkcja):... self.funkcja = funkcja... def call (self, *args, **kwargs):... print "wywołanie", self.funkcja. name... x = self.funkcja(*args, **kwargs)... print self.funkcja. name, "zwróciła", x... return x >>> @logged... def f():... return g() + g() >>> @logged

... def g():... return 1 >>> f() wywołanie f wywołanie g g zwróciła 1 wywołanie g g zwróciła 1 f zwróciła 2 2 Tutaj mamy taką sytuację, że nasz obiekt klasy dekorującej podstawiamy za dekorowany obiekt, i wywołanie f() czy g(), wywołuje naprawdę logged. call, a dopiero pośrednio oryginalną funkcję. Dekoratora zwracające oryginalną funkcję i dekoratory zwracające inny obiekt Dwa poprzednie przykłady różnią się w istotny sposób. Pierwszy dekorator, ustaw_atrybut_xxx, zwraca przekazany mu obiekt, lekko tylko go zmieniając. Natomiast drugi dekorator, logged, zwraca inny wywoływalny obiekt instancję logged który zostaje dowiązany pod nazwą oryginalnej funkcji. Obie wersje są dozwolone, i obie wersje są użyteczne, w zależności od sytuacji. W pierwszej wersji działanie dekoratora ogranicza się do momentu definicji funkcji i wywołania dekoratora. Oznacza to, że dekorator może ustawić atrybut na funkcji, wypisać komunikat, czy dopisać funkcję do jakiegoś rejestru, ale nie może wpływać na sposób działania funkcji. Bardziej interesująca jest druga wersja, gdzie możliwe są nie tylko operacje w trakcie definicji funkcji, ale możliwe jest w zasadzie nieograniczone oddziaływanie na każde wywołanie funkcji. Przewagą pierwszej wersji nad drugą jest prostota i wydajność nie tylko definicja dekoratora jest prostsza, ale również lista funkcji widoczna w komunikacie o wyjątku nie zawiera funkcji dekorującej, której obecność może być niespodzianką dla użytkownika, zwłaszcza że często jest to anonimowa funkcja tworzona przy każdym wywołaniu dekoratora działanie programu jest minimalnie szybsze, bo unikamy niewielkiego narzutu na każde wywołanie. Do czego (i czy wogóle) warto używać dekoratorów? Ponieważ już mniej więcej wiemy jak się definiuje dekoratory, pora odpowiedzieć na pytanie, czy i dlaczego warto je wykorzystywać. W przypadku logged, z całą pewnością moglibyśmy wstawić odpowiednie wyrażenia print na początek i koniec każdej z definiowanych funkcji. Wykorzystanie dekoratorów pozwala na rozdzielenie sfer odpowiedzialności pomiędzy właściwe funkcje (dokonujące "obliczeń") oraz funkcję wypisującą komunikaty. W przypadku mniej trywialnych funkcji powoduje to uproszczenie kodu i ułatwia jego zrozumienie. Zaletą jest też to, że unikamy duplikacji zamiast

identycznych poleceń print w każdej funkcji, piszemy je tylko raz, a następnie "wstawiamy", dodając jedną linijkę wywołującą dekorator. Przykłady funkcjonalności jaką można zaimplementować w formie dekoratorów obejmuje przechowywanie wykonanych wcześniej obliczeń w celu przyspieszenia działania programu, oznaczanie funkcji jako "przestarzałych" (ang. deprecated) i wypisywania ostrzeżenia przy pierwszym wywołaniu, pomiar czasu działania funkcji i oczywiście wiele innych Przydatne linki Python Decorator Library moduł functools Prezentacja o dekoratorach, wyjątkach i context managers moduł decorator