poniedziałek, 8 maja 2017

[DSP2017] 21# Romans z Pythonem cz.3 (moduły, wyjątki, obiekty iterowane, klasy, dziedziczenie, pliki i zarządzanie zasobami)

Pomimo, że rzeczywistość rozszerzona w HoloLens jest zasadniczym tematem dla DSP 2017, o tyle pewien romans z Pythonem również pomału się rozwija. Dziś podzielę się notatkami z kolejnych obszarów Pythona, jakie powstały podczas ich poznawania i praktycznego testowania w Visual Studio 2017 15.2. Nie są to oczywiście wszystkie tajemnice, jakie skrywa ten język, ale powinno wystarczyć to do napisania jakiegoś prostego skryptu. Przedstawiłem tu także klasy i dziedziczenie, które przydadzą się raczej w czymś większym, ale warto być świadomym jak to wygląda.  Trochę to przekombinowali i są pułapki tam, gdzie normalnie ich nie ma.

python_logoball-python

7# Moduły

Jeśli w pliku modułu będzie kod wykonywalny,

image

to wykona się podczas importu:

image

Po zdefiniowaniu funkcji w module:

image

taka sytuacja nie ma miejsca, a funkcję można wywołać albo po imporcie całego modułu:

image

albo po imporcie samej funkcji z modułu:

image

Podobnie jest z importem funkcji statycznych w C# 6.

Możemy też zaimportować wszystkie elementy z modułu pisząc *.

Import relatywny - jeśli importujemy moduł zawarty w bieżącym module (pomijamy nazwę głównego modułu i zaczynamy nazwę od . w tym samym folderze, dwie kropki stosujemy przy odwołaniu do rodzica)

Moduł może się nazywać jak plik lub __main__ (jeśli jesteśmy w skrypcie uruchomionym przez python.exe). Do odczytu służy specjalna zmienna __name__ . Ten sam plik może pełnić funkcję modułu lub skryptu (wywołanie funkcji w zależności czy __name__ == __main__). Może być też zdefiniowana funkcja main. Argumenty przekazywane do skryptu są dostępne jako sys.argv[i]. Istnieje także standardowa bliblioteka argparse.

Dokumentowanie funkcji - pod linijką z definicją opis umieszczamy w potrójnym cudzysłowie, możliwe sekcje Args  i  Returns.

image

Dokumentowanie modułu - na początku pliku, możliwa sekcja Usage.

Komentarz przy linii:

image

Jeśli skrypt rozpoczyna się od linii:

image

to może być wykonany w konsoli za pomocą Python 2 lub 3 przez wpisanie swojej nazwy z rozszerzeniem .py.  Działa to także na Windows.

Pakiet - moduł, który zawiera inne moduły (i pakiety).

Moduły to zwykle pliki, a pakiety to zwykle katalogi. Katalog powinien być w sys.path.

Plik inicjujący dla pakietu: __init__.py

Namespace packages są podzielone na kilka folderów, nie zawierają pliku __init__.py

 

#8 Wyjątki

Coś ala try catch, tylko try except.

image

Nie łapiemy zwykle błędów programowania tj. IndentationError, SyntaxError i NameError. Unikamy obsługi błędów TypeError.

Blok except może nie mieć podanej nazwy błędu.

W bloku except można użyć słowa “pass” (akceptuj i nic nie rób).

Wyrażenie except można zakończyć frazą “as zmienna”.

Wyjątek można ponownie wyrzucić z bloku except za pomocą słowa “raise”.

Istnieje też blok finally.

Try except można stosować też na poziomie modułu (alternatywny import pakietów i inne definicje funkcji).

Można tworzyć własne klasy wyjątków dziedziczące po Exception.

Wyrzucanie wyjątku - raise {obiekt wyjątku}

 

#9 Obiekty iterowane

Szybkie stworzenie nowej listy: [ expr(item) for item in iterable ]

image

{} zamiast [] jeśli chcemy zbiór unikalnych wartości

opcjonalne filtrowanie: [ expr(item) for item in iterable if predicate(item) ]

Szybkie tworzenie słownika: { key_expr:value_expr for item in iterable }

protokoły Iterable i Iterator:

iterator = iter(iterable)

item = next(iterator)

Generatory

image

można używać w pętli for

wyrażenie generatora: ( expr(item) for item in iterable )

można to powielić:

image

szybka suma:

image

itertools - funkcje dla obiektów iterable

wbudowane np. sum, min, max, map, filter, any, all, zip

filtrowanie:

image

moduł itertools np. count, islice

image

moduł functools np. reduce

image

 

10# Klasy

Definicja minimalistyczna:

image

image

W metodach instancyjnych zawsze pierwszym parametrem jest obiekt self.

image

image

Można też zrobić wywołanie na klasie:

image

Klasa może mieć inicjalizator, nie konstruktor:

image

image

Powyższe linijki nie chciały mi się długo wykonać w VS 2017 15.2 Preview. Cały czas jakby nie była odświeżona definicja klasy o inicjalizator z parametrem name. Pomogło dopiero ponowne uruchomienie Visual Studio. Pamiętajmy jednak że to właśnie Preview, a nie wersja finalna.

W Python wszystkie składowe klas są publiczne.

W inicjalizatorze można wyrzucać wyjątki.

W wywołaniu metody można jawnie podać nazwy parametrów.

Atrybut klasowy (nie instancji klasy):

image

image

Metoda statyczna:

image

Zamiast niej można użyć metody klasowej:

image

Metody klasowe mogą służyć jako nazwane konstruktory. Do klasy A można dodać:

image

co pozwala na:

image

Polimorfizm – wystarczy by klasy miały te same składowe.

Dziedziczenie przydaje się głównie do współdzielenia implementacji.

image

Item - klasa bazowa

Klasa abstrakcyjna - nie ma zdefiniowanych wszystkich używanych przez siebie składowych, może być utworzona, najwyżej gdzieś wystąpi błąd.

image

Więcej współdzielenia kodu:

image

Metody statyczne w klasach pochodnych mogą być nadpisywane (po prostu są jeszcze raz definiowane).

Jeśli klasa pochodna nie ma inicjalizatora, to zostanie wywołany z klasy bazowej.

W inicjalizatorze klasy pochodnej możemy wywołać inicjalizator klasy bazowej (nie dzieje się to automatycznie). Klasa B dziedzicząca po wyżej przedstawionej klasie A może wyglądać następująco:

image

Stworzenie przez inicjalizator zadziała. Błąd wystąpi, gdy będziemy chcieli skorzystać z metody create_empty:

image

Wtedy w klasie bazowej A trzeba zmodyfikować nieco definicję create_empty:

image

image

Propercje:

W klasie B _system można opakować w getter i setter:

image

W przypadku settera nazwa atrybutu zaczyna się od nazwy gettera. Visual Studio 2017 Preview 15.2 nie podświetliło go jeszcze.

image

Przy dziedziczeniu getterów i setterów trzeba uważać. Przy definicji:

image

wszystko nam zadziała:

image

ale  gdyby był sam setter w klasie C, to trzeba by zmienić atrybut nad nim na:

image

Z kolei, gdy zostawimy taki atrybut nad setterem w klasie C, a będzie tam getter taki jak na początku, to zamiast niego będzie wywoływał się ten z klasy bazowej!

Problem z wywołaniem settera klasy bazowej w setterze klasy pochodnej.

image

image

Pomoże tutaj jawne wywołanie funkcji settera z klasy bazowej:

image

Sprawdzanie czy obiekt jest danej klasy:

image

Sprawdzenie czy dana klasa dziedziczy z innej klasy:

image

Każda klasa dziedziczy po wbudowanym typie object.

W Pythonie można dziedziczyć po wielu klasach równocześnie

  • Jeśli klasa pochodna nie ma inicjalizatora, to wywoływany jest z pierwszej klasy bazowej
  • składowa __bases__ – krotka klas bazowych
  • składowa __mro__ lub mro() – “method resolution order”, szukana jest pasująca metoda po kolei w klasach według MRO, brana jest pierwsza znaleziona, MRO zależy od kolejności podania klas bazowych w definicji klasy, MRO wylicza Python w oparciu o algorytm C3
  • super() zwraca rozwiązania metod z klas za daną klasą w MRO

 

11# Pliki i zarządzanie zasobami

Pliki - odczyt i zapis w trybie binarnym i tekstowym, różne tryby np. czyszczenie przed zapisem lub dopisywanie na końcu itp.

Przykładowy zapis do pliku tekstowego:

image

Można też jednorazowo zapisać listę linii za pomocą funkcji writelines().

Odczyt:

image

Korzystanie z pliku kończymy tak jak poprzednio wywołaniem funkcji close. Można odczytywać daną liczbę znaków (np. read(5)), cały plik (read()), linię (readline()) lub wszystkie linie w formie listy (readlines()).

Zamiast print() można użyć sys.stdout.write() z modułu sys. Pozwala to uniknąć podwójnych odstępów między liniami, jeśli linia kończyła się na ‘\n’:

image

Funkcja open() zwraca menadżera kontekstu. Powyższy kod lepiej zapisać w bloku with, który zamyka plik także po wystąpieniu błędu podczas odczytu (ręcznie do obsługi tego trzeba by użyć bloku try finally).

image

image

Inne obiekty podobne do plików:

image

Można też samemu zdefiniować menadżera kontekstu, ale nie będziemy się teraz w to wgłębiać.

 

Myślę, że starczy tego Pythona na dziś. Następnym razem, jeśli będę coś o nim pisał, pójdziemy w jakiś przykład praktycznego zastosowania.

Brak komentarzy: