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.
7# Moduły
Jeśli w pliku modułu będzie kod wykonywalny,
to wykona się podczas importu:
Po zdefiniowaniu funkcji w module:
taka sytuacja nie ma miejsca, a funkcję można wywołać albo po imporcie całego modułu:
albo po imporcie samej funkcji z modułu:
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.
Dokumentowanie modułu - na początku pliku, możliwa sekcja Usage.
Komentarz przy linii:
Jeśli skrypt rozpoczyna się od linii:
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.
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 ]
{} 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
można używać w pętli for
wyrażenie generatora: ( expr(item) for item in iterable )
można to powielić:
szybka suma:
itertools - funkcje dla obiektów iterable
wbudowane np. sum, min, max, map, filter, any, all, zip
filtrowanie:
moduł itertools np. count, islice
moduł functools np. reduce
10# Klasy
Definicja minimalistyczna:
W metodach instancyjnych zawsze pierwszym parametrem jest obiekt self.
Można też zrobić wywołanie na klasie:
Klasa może mieć inicjalizator, nie konstruktor:
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):
Metoda statyczna:
Zamiast niej można użyć metody klasowej:
Metody klasowe mogą służyć jako nazwane konstruktory. Do klasy A można dodać:
co pozwala na:
Polimorfizm – wystarczy by klasy miały te same składowe.
Dziedziczenie przydaje się głównie do współdzielenia implementacji.
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.
Więcej współdzielenia kodu:
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:
Stworzenie przez inicjalizator zadziała. Błąd wystąpi, gdy będziemy chcieli skorzystać z metody create_empty:
Wtedy w klasie bazowej A trzeba zmodyfikować nieco definicję create_empty:
Propercje:
W klasie B _system można opakować w getter i setter:
W przypadku settera nazwa atrybutu zaczyna się od nazwy gettera. Visual Studio 2017 Preview 15.2 nie podświetliło go jeszcze.
Przy dziedziczeniu getterów i setterów trzeba uważać. Przy definicji:
wszystko nam zadziała:
ale gdyby był sam setter w klasie C, to trzeba by zmienić atrybut nad nim na:
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.
Pomoże tutaj jawne wywołanie funkcji settera z klasy bazowej:
Sprawdzanie czy obiekt jest danej klasy:
Sprawdzenie czy dana klasa dziedziczy z innej klasy:
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:
Można też jednorazowo zapisać listę linii za pomocą funkcji writelines().
Odczyt:
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’:
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).
Inne obiekty podobne do plików:
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:
Prześlij komentarz