Python Workshop
Transkrypt
Python Workshop
Python Workshop Release 3f9e170, 2017-02-21 Matt Harasymczuk 2017-02-21 Wst˛ep 1 Author 2 Wst˛ep 2.1 O j˛ezyku Python . . . . . . . . . . . . . . . . . 2.1.1 Co to jest Python . . . . . . . . . . . . 2.1.2 Historia Pythona . . . . . . . . . . . . 2.1.3 Read–Eval–Print Loop . . . . . . . . . 2.1.4 Rozszerzenia plików Pythona . . . . . . 2.2 Instalacja . . . . . . . . . . . . . . . . . . . . . 2.2.1 Którego wersj˛e wybrać? . . . . . . . . 2.2.2 Który interpreter? . . . . . . . . . . . . 2.2.3 Instalacja . . . . . . . . . . . . . . . . 2.2.4 PYTHON_PATH . . . . . . . . . . . . 2.3 Podstawy składni j˛ezyka . . . . . . . . . . . . . 2.3.1 Ehlo World! . . . . . . . . . . . . . . . 2.3.2 Deklaracje na poczatku ˛ pliku . . . . . . 2.3.3 Wci˛ecia zamiast nawiasów klamrowych 2.3.4 Końce linii . . . . . . . . . . . . . . . 2.3.5 Duck typing . . . . . . . . . . . . . . . 2.3.6 Komentarze . . . . . . . . . . . . . . . 2.4 Virtualenv . . . . . . . . . . . . . . . . . . . . 2.4.1 Tworzenie wirtualnego środowiska . . . 2.4.2 Aktywacja i korzystanie ze środowiska . 2.4.3 Pakiety i zależności . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 3 3 3 4 4 5 5 5 6 7 7 7 7 8 8 8 9 10 10 11 11 Podstawy 3.1 Stałe, zmienne i typy danych . . . . . . . . 3.1.1 Stałe i zmienne . . . . . . . . . . 3.1.2 Numeryczne typy danych . . . . . 3.1.3 Tekstowe typy danych . . . . . . 3.1.4 Logiczne typy danych . . . . . . . 3.1.5 Złożone typy danych . . . . . . . 3.1.6 Rozszerzone typy danych . . . . . 3.1.7 Jak inicjować poszczególne typy? 3.2 Instrukcje warunkowe . . . . . . . . . . . 3.2.1 if ... elif ... else . . . . . . . 3.2.2 not, in, is . . . . . . . . . . . 3.2.3 switch statement? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 13 13 13 14 15 15 15 15 16 16 16 16 3 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . i 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 ii P˛etle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.1 Wybitnie użyteczne p˛etla for . . . . . . . . . . . . . . 3.3.2 while . . . . . . . . . . . . . . . . . . . . . . . . . . Funkcje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.4.1 Definiowanie funkcji . . . . . . . . . . . . . . . . . . . 3.4.2 Konwencja nazewnicza funkcji . . . . . . . . . . . . . . 3.4.3 Argumenty do funkcji . . . . . . . . . . . . . . . . . . . 3.4.4 Zwracanie wartości . . . . . . . . . . . . . . . . . . . . 3.4.5 Operator * i ** . . . . . . . . . . . . . . . . . . . . . . Funkcje wbudowane i słowa kluczowe . . . . . . . . . . . . . . . 3.5.1 Słowa kluczowe . . . . . . . . . . . . . . . . . . . . . . 3.5.2 Wszystkie funkcje wbudowane . . . . . . . . . . . . . . 3.5.3 Funkcje wbudowane . . . . . . . . . . . . . . . . . . . Operatory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.6.1 Lista operatorów . . . . . . . . . . . . . . . . . . . . . 3.6.2 Operacje na typach numerycznych . . . . . . . . . . . . 3.6.3 Kolejność operatorów . . . . . . . . . . . . . . . . . . . Pliki . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.7.1 Konstrukcja with . . . . . . . . . . . . . . . . . . . . 3.7.2 Czytanie . . . . . . . . . . . . . . . . . . . . . . . . . . 3.7.3 Zapis . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.7.4 Tryby odczytu i zapisu . . . . . . . . . . . . . . . . . . 3.7.5 Obsługa wyjatków ˛ . . . . . . . . . . . . . . . . . . . . Doctesty . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Print formatting . . . . . . . . . . . . . . . . . . . . . . . . . . 3.9.1 Stary styl - %s . . . . . . . . . . . . . . . . . . . . . . . 3.9.2 Nowy styl - .format() . . . . . . . . . . . . . . . . . 3.9.3 f-strings - Python >= 3.6 . . . . . . . . . . . . . . . . . 3.9.4 Wi˛ecej informacji . . . . . . . . . . . . . . . . . . . . . Logowanie zdarzeń . . . . . . . . . . . . . . . . . . . . . . . . . 3.10.1 Poziomy logowania . . . . . . . . . . . . . . . . . . . . 3.10.2 Korzystanie z logging . . . . . . . . . . . . . . . . . 3.10.3 Konfiguracja logowania . . . . . . . . . . . . . . . . . . 3.10.4 Konfiguracja formatowania logów . . . . . . . . . . . . Programowanie obiektowe . . . . . . . . . . . . . . . . . . . . . 3.11.1 Paradygmat Obiektowy . . . . . . . . . . . . . . . . . . 3.11.2 Składnia . . . . . . . . . . . . . . . . . . . . . . . . . . 3.11.3 Przecia˛żanie operatorów . . . . . . . . . . . . . . . . . 3.11.4 Dobre praktyki . . . . . . . . . . . . . . . . . . . . . . Serializacja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.12.1 pickle . . . . . . . . . . . . . . . . . . . . . . . . . . 3.12.2 json . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.12.3 csv . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.12.4 xml . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.12.5 xslt . . . . . . . . . . . . . . . . . . . . . . . . . . . . Wyjatki ˛ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.13.1 Po co sa˛ wyjatki? ˛ . . . . . . . . . . . . . . . . . . . . . 3.13.2 Najpopularniejsze wyjatki ˛ . . . . . . . . . . . . . . . . 3.13.3 Przechwytywanie wyjatków ˛ . . . . . . . . . . . . . . . 3.13.4 Hierarchia wyjatków ˛ . . . . . . . . . . . . . . . . . . . Dobre praktyki . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.14.1 PEP20 - Zen of Python . . . . . . . . . . . . . . . . . . 3.14.2 PEP8 . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.14.3 Korzystanie z help(), dir() i object.__dict__ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 16 16 16 16 16 16 17 18 19 19 20 20 20 20 21 21 21 21 21 22 22 22 22 23 23 23 23 23 23 23 24 24 25 25 25 27 27 28 28 28 28 28 29 30 31 31 31 31 31 33 33 34 39 3.14.4 Kilka przykaładów z praktyki . . . . 3.14.5 Magic number i Magic string . . . . . 3.14.6 Passowords . . . . . . . . . . . . . . 3.14.7 Wczytywanie konfiguracji programów 3.14.8 Wersjonowanie API . . . . . . . . . . 3.15 Zadania . . . . . . . . . . . . . . . . . . . . . 3.15.1 Powielanie napisów . . . . . . . . . . 3.15.2 Parzystość . . . . . . . . . . . . . . . 3.15.3 Liczby całkowite . . . . . . . . . . . 3.15.4 Dzienniczek ucznia . . . . . . . . . . 3.15.5 Przeliczenia trygonometryczne . . . . 3.15.6 Wyrazy . . . . . . . . . . . . . . . . 3.15.7 Lotto . . . . . . . . . . . . . . . . . 3.15.8 Przeliczanie temperatury . . . . . . . 3.15.9 Pole trójkata ˛ . . . . . . . . . . . . . . 3.15.10 Wyliczanie średniej dla parametrów . 3.15.11 Konwersja liczby na zapis słowny . . 3.15.12 Rzymskie . . . . . . . . . . . . . . . 3.15.13 map(), filter() i lambda . . . 3.15.14 Zawartość pliku . . . . . . . . . . . . 3.15.15 Ksia˛żka adresowa . . . . . . . . . . . 3.15.16 Zbalansowanie nawiasów . . . . . . . 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 39 39 39 39 39 39 40 40 40 41 41 41 41 42 42 42 43 43 43 43 44 Średniozaawansowany 4.1 Biblioteka standardowa . . . . . . . . . . . . . 4.1.1 datetime . . . . . . . . . . . . . . . 4.1.2 time . . . . . . . . . . . . . . . . . . 4.1.3 os . . . . . . . . . . . . . . . . . . . . 4.1.4 sys . . . . . . . . . . . . . . . . . . . 4.1.5 warnings . . . . . . . . . . . . . . . 4.1.6 pprint . . . . . . . . . . . . . . . . . 4.1.7 csv . . . . . . . . . . . . . . . . . . . 4.1.8 memoize . . . . . . . . . . . . . . . . 4.1.9 json . . . . . . . . . . . . . . . . . . 4.1.10 sqlite . . . . . . . . . . . . . . . . . 4.1.11 re . . . . . . . . . . . . . . . . . . . . 4.1.12 httplib . . . . . . . . . . . . . . . . 4.1.13 urllib . . . . . . . . . . . . . . . . . 4.1.14 socket . . . . . . . . . . . . . . . . . 4.1.15 tempfile . . . . . . . . . . . . . . . 4.1.16 io . . . . . . . . . . . . . . . . . . . . 4.1.17 functools . . . . . . . . . . . . . . 4.1.18 itertools . . . . . . . . . . . . . . 4.1.19 math . . . . . . . . . . . . . . . . . . 4.1.20 statistics . . . . . . . . . . . . . 4.1.21 random . . . . . . . . . . . . . . . . . 4.1.22 subprocess . . . . . . . . . . . . . 4.1.23 doctest . . . . . . . . . . . . . . . . 4.1.24 Collections . . . . . . . . . . . . . . . 4.2 Biblioteki zewn˛etrzne . . . . . . . . . . . . . . 4.2.1 Do zastosowań naukowych . . . . . . . 4.2.2 Wspierajacych ˛ programowanie sieciowe 4.2.3 Google App Engine . . . . . . . . . . . 4.2.4 Bazy danych . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 47 47 47 47 47 47 48 48 48 48 48 48 49 49 49 49 49 49 49 49 49 49 49 50 50 50 50 50 52 52 iii 4.2.5 Inne . . . . . . . . . . . . . . . . . . . . . . . . Parametry linii poleceń . . . . . . . . . . . . . . . . . . . 4.3.1 argparse . . . . . . . . . . . . . . . . . . . . 4.3.2 Uruchamianie poleceń . . . . . . . . . . . . . . 4.3.3 Timeout dla wykonywania poleceń . . . . . . . . 4.3.4 Parsowanie i sanityzacja argumentów . . . . . . 4.4 Modularyzacja, wersjonowanie i dystrybucja . . . . . . . 4.4.1 Modularyzacja . . . . . . . . . . . . . . . . . . 4.4.2 Tworzenie paczek . . . . . . . . . . . . . . . . . 4.4.3 Instalacja i korzystanie z zewn˛etrznych bibliotek 4.4.4 Przyszłość paczkowania i dystrybucji . . . . . . 4.5 Wyrażenia regularne . . . . . . . . . . . . . . . . . . . . 4.5.1 Konstruowanie wyrażeń . . . . . . . . . . . . . 4.5.2 Wyciaganie ˛ parametrów (zmiennych) . . . . . . 4.5.3 Najcz˛eściej wykorzystywane funkcje . . . . . . . 4.5.4 Greedy search . . . . . . . . . . . . . . . . . . . 4.6 Testy . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.6.1 Doctest . . . . . . . . . . . . . . . . . . . . . . 4.6.2 Unit Test . . . . . . . . . . . . . . . . . . . . . 4.6.3 selenium . . . . . . . . . . . . . . . . . . . . 4.6.4 Mock . . . . . . . . . . . . . . . . . . . . . . . 4.6.5 Stub . . . . . . . . . . . . . . . . . . . . . . . . 4.7 Tworzenie dokumentacji . . . . . . . . . . . . . . . . . . 4.7.1 Format reStructuredText . . . . . . . . . . . . . 4.7.2 reStructuredText vs. Markdown . . . . . . . . . 4.7.3 Sphinx . . . . . . . . . . . . . . . . . . . . . . . 4.8 Django . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.8.1 Co to jest Django? . . . . . . . . . . . . . . . . 4.8.2 Architektura aplikacji Django . . . . . . . . . . 4.8.3 Modele . . . . . . . . . . . . . . . . . . . . . . 4.8.4 Widoki . . . . . . . . . . . . . . . . . . . . . . 4.8.5 Panel admina . . . . . . . . . . . . . . . . . . . 4.8.6 Dokumentacja . . . . . . . . . . . . . . . . . . . 4.8.7 Widoki generyczne . . . . . . . . . . . . . . . . 4.8.8 Localization . . . . . . . . . . . . . . . . . . . . 4.8.9 Sygnały . . . . . . . . . . . . . . . . . . . . . . 4.8.10 Migracje schematów bazy danych . . . . . . . . 4.8.11 Management Commands . . . . . . . . . . . . . 4.8.12 ORM . . . . . . . . . . . . . . . . . . . . . . . 4.8.13 Skrypty z Django . . . . . . . . . . . . . . . . . 4.9 Projektowanie GUI . . . . . . . . . . . . . . . . . . . . . 4.9.1 Biblioteka Tkinter . . . . . . . . . . . . . . . . . 4.10 Introspekcja . . . . . . . . . . . . . . . . . . . . . . . . 4.10.1 Pola obiektu . . . . . . . . . . . . . . . . . . . . 4.10.2 Metody obiektu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 54 54 55 55 55 56 56 56 57 57 58 58 58 58 58 58 58 59 60 60 60 60 60 61 61 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 65 65 65 Zaawansowany 5.1 Generatory i list comprehension . 5.1.1 List comprehension . . . 5.1.2 Generator expressions . . 5.1.3 Operator yield . . . . 5.2 Iteratory . . . . . . . . . . . . . 5.2.1 Czym jest iterator? . . . 5.2.2 Iterowanie po obiektach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 67 67 67 67 68 68 68 4.3 5 iv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 69 69 69 69 69 69 69 69 69 72 73 73 73 74 75 75 75 75 75 75 75 75 76 76 76 76 76 76 76 76 76 77 79 79 80 80 81 Załaczniki ˛ 6.1 Przydatne odnośniki . . . . . . . . . . . . . . . . . 6.1.1 Doumentacja . . . . . . . . . . . . . . . . 6.1.2 Video . . . . . . . . . . . . . . . . . . . . 6.1.3 Środowisko developerskie . . . . . . . . . 6.1.4 Ponadto . . . . . . . . . . . . . . . . . . . 6.1.5 Humor IT . . . . . . . . . . . . . . . . . . 6.1.6 Inne . . . . . . . . . . . . . . . . . . . . . 6.2 Python 2 vs. 3 . . . . . . . . . . . . . . . . . . . . 6.2.1 six . . . . . . . . . . . . . . . . . . . . . 6.2.2 Lista kompatybilności Python 2 i Python 3 . 6.2.3 Unicode i kodowanie znaków . . . . . . . . 6.2.4 Biblioteki standardowe w 2 i 3 . . . . . . . 6.2.5 Python 3.5 i deklaracja typów . . . . . . . 6.3 Wybór IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 83 83 83 83 83 83 84 85 85 85 85 85 86 86 5.3 5.4 5.5 5.6 5.7 5.8 5.9 6 5.2.3 Własny iterator . . . . . . . . . . . System Operacyjny . . . . . . . . . . . . . . 5.3.1 eval . . . . . . . . . . . . . . . . 5.3.2 sys.platform . . . . . . . . . . 5.3.3 sys.exit() . . . . . . . . . . . 5.3.4 subprocess . . . . . . . . . . . Kolejki, watki ˛ i procesy . . . . . . . . . . . 5.4.1 Kolejki . . . . . . . . . . . . . . . 5.4.2 Watki ˛ a procesy . . . . . . . . . . . 5.4.3 Watki ˛ . . . . . . . . . . . . . . . . 5.4.4 Procesy . . . . . . . . . . . . . . . Programowanie funkcyjne . . . . . . . . . . 5.5.1 lambda . . . . . . . . . . . . . . . 5.5.2 closure . . . . . . . . . . . . . . . . 5.5.3 decorator . . . . . . . . . . . . . . 5.5.4 złożenia funkcji . . . . . . . . . . . 5.5.5 map() . . . . . . . . . . . . . . . 5.5.6 zip() . . . . . . . . . . . . . . . 5.5.7 filter() . . . . . . . . . . . . . 5.5.8 all() . . . . . . . . . . . . . . . 5.5.9 any() . . . . . . . . . . . . . . . Programowanie sieciowe . . . . . . . . . . . 5.6.1 Socket . . . . . . . . . . . . . . . . 5.6.2 Prosty serwer HTTP . . . . . . . . 5.6.3 httplib . . . . . . . . . . . . . . 5.6.4 urllib . . . . . . . . . . . . . . . 5.6.5 smtp . . . . . . . . . . . . . . . . 5.6.6 HTML Scrapping . . . . . . . . Wzorce projektowe . . . . . . . . . . . . . . 5.7.1 Wzorce kreacyjne . . . . . . . . . . C Extensions . . . . . . . . . . . . . . . . . 5.8.1 C Types . . . . . . . . . . . . . . . 5.8.2 C Modules . . . . . . . . . . . . . Zadania . . . . . . . . . . . . . . . . . . . . 5.9.1 REST API . . . . . . . . . . . . . . 5.9.2 Generatory vs. Przetwarzanie Listy 5.9.3 Wielowatkowość ˛ . . . . . . . . . . 5.9.4 Mini Botnet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v . . . . . . . . . . . . 86 87 87 89 90 90 90 90 90 90 90 91 Receptury 7.1 LDAP Expiring Passwords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 93 6.4 6.5 6.6 7 vi 6.3.1 Czym jest IDE? . . . . . Ekosystem Narz˛ediowy . . . . . 6.4.1 Code Quality . . . . . . 6.4.2 Automation and Releases 6.4.3 Testy Mutacyjne . . . . 6.4.4 Transifex . . . . . . . . Ksia˛żki . . . . . . . . . . . . . . 6.5.1 Design patterns . . . . . 6.5.2 Refactoring . . . . . . . 6.5.3 Quality . . . . . . . . . 6.5.4 Python . . . . . . . . . . Python WAT?! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . CHAPTER 1 Author name Matt Harasymczuk email [email protected] www http://www.astrotech.io facebook https://facebook.com/matt.harasymczuk linkedin https://linkedin.com/in/mattharasymczuk 1 Python Workshop, Release 3f9e170, 2017-02-21 2 Chapter 1. Author CHAPTER 2 Wstep ˛ O jezyku ˛ Python Co to jest Python Python - j˛ezyk programowania wysokiego poziomu ogólnego przeznaczenia, o rozbudowanym pakiecie bibliotek standardowych, którego idea˛ przewodnia˛ jest czytelność i klarowność kodu źródłowego. Jego składnia cechuje si˛e przejrzystościa˛ i zwi˛ezłościa.˛ Python wspiera różne paradygmaty programowania: obiektowy, imperatywny oraz w mniejszym stopniu funkcyjny. Posiada w pełni dynamiczny system typów i automatyczne zarzadzanie ˛ pami˛ecia,˛ b˛edac ˛ w tym podobnym do j˛ezyków Perl, Ruby, Scheme czy Tcl. Podobnie jak inne j˛ezyki dynamiczne jest cz˛esto używany jako j˛ezyk skryptowy. Interpretery Pythona sa˛ dost˛epne na wiele systemów operacyjnych. Python rozwijany jest jako projekt Open Source zarzadzany ˛ przez Python Software Foundation, która jest organizacja˛ non-profit. Fragment pochodzi z serwisu Wikipedia. Historia Pythona Pythona stworzył we wczesnych latach 90. Guido van Rossum - jako nast˛epc˛e j˛ezyka ABC, stworzonego w Centrum voor Wiskunde en Informatica (CWI – Centrum Matematyki i Informatyki w Amsterdamie). Van Rossum jest głównym twórca˛ Pythona, choć spory wkład w jego rozwój pochodzi od innych osób. Z racji kluczowej roli, jaka˛ van Rossum pełni przy podejmowaniu ważnych decyzji projektowych, cz˛esto określa si˛e go przydomkiem “Benevolent Dictator for Life” (BDFL). Nazwa j˛ezyka nie pochodzi od zwierz˛ecia, jak można przypuszczać. Python pochodzi od serialu komediowego emitowanego w latach siedemdziesiatych ˛ przez BBC. Ten serial nosi nazw˛e “Monty Python’s Flying Circus” (Latajacy ˛ Cyrk Monty Pythona). Projektant potrzebował nazwy, która była krótka, unikalna i nieco tajemnicza. Na dodatek był fanem serialu, wi˛ec uważał, że taka nazwa dla j˛ezyka była świetna. Wersja 1.2 była ostatnia˛ wydana˛ przez CWI. Od 1995 roku Van Rossum kontynuował prac˛e nad Pythonem w Corporation for National Research Initiatives (CNRI) w Reston w Wirginii, gdzie wydał kilka wersji Pythona, do 1.6 włacznie. ˛ W 2000 roku van Rossum i zespół pracujacy ˛ nad rozwojem jadra ˛ Pythona przenieśli si˛e do BeOpen.com by założyć zespół BeOpen PythonLabs. Pierwsza˛ i jedyna˛ wersja˛ wydana˛ przez BeOpen.com był Python 2.0. Po wydaniu wersji 1.6 i opuszczeniu CNRI przez van Rossuma, który zajał ˛ si˛e programowaniem komercyjnym, uznano za wysoce pożadane, ˛ by Pythona można było używać z oprogramowaniem dost˛epnym 3 Python Workshop, Release 3f9e170, 2017-02-21 na licencji GPL. CNRI i Free Software Foundation (FSF) podj˛eły wspólny wysiłek w celu odpowiedniej modyfikacji licencji Pythona. Wersja 1.6.1 była zasadniczo identyczna z wersja˛ 1.6, z wyjatkiem ˛ kilku drobnych poprawek oraz licencji, dzi˛eki której późniejsze wersje mogły być zgodne z licencja˛ GPL. Python 2.1 pochodzi zarówno od wersji 1.6.1, jak i 2.0. Po wydaniu Pythona 2.0 przez BeOpen.com Guido van Rossum i inni programiści z PythonLabs przeszli do Digital Creations. Cała własność intelektualna dodana od tego momentu, poczawszy ˛ od Pythona 2.1 (wraz z wersjami alpha i beta), jest własnościa˛ Python Software Foundation (PSF), niedochodowej organizacji wzorowanej na Apache Software Foundation. Fragment pochodzi z serwisu Wikipedia. Read–Eval–Print Loop Python spopularyzował wykorzystanie tzw. interpretera REPL (read–eval–print loop). REPL to interaktywny interpreter poleceń wykonujacy ˛ wyrażenia z j˛ezyka (zwykle linie), których wyniki sa˛ wyświetlane użytkownikowi natychmiast po ich wykonaniu. W uproszczeniu można powiedzieć, że REPL jest to linia poleceń programu python. Znakiem zach˛ety do wprowadzania tekstu takiego programu sa˛ trzy znaki wi˛ekszości >>>. Polecenia wpisane po tych znaczkach sa˛ interpretowane i natychmiast wykonywane. Ich wynik przedstawiany jest w nast˛epnej linijce. Jeżeli wykorzystamy konstrukcj˛e, która wymaga wi˛ecej niż jednej linii, każda kolejna linijka b˛edzie poprzedzona trzema kropkami .... Przykłady takiej interakcji zobaczymy przy omawianiu “Hello World”. Rozwiazanie ˛ REPL idealnie pasuje do szybkiego testowania składni oraz funkcjonalności programów i bibliotek. Dzi˛eki REPL jesteśmy w stanie przeprowadzić interaktywna˛ sesj˛e z linia˛ poleceń a po przetestowaniu rozwiazania ˛ wkleić działajace ˛ linie do naszego skryptu. Taki styl znaczaco ˛ przyspiesza development i debugging. Uproszczona˛ implementacj˛e takiego rozwiazania ˛ można przedstawić w nast˛epujacy ˛ sposób: while True: command = raw_input('>>> ') output = eval(command) print(output) W dalszej cz˛eści omówimy poszczególne elementy, które sa˛ tu wymienione. Rozszerzenia plików Pythona Pliki źródłowe j˛ezyka Python zarówno w wersji 2 jak i 3 maja˛ rozszerzenie .py. Podczas wytwarzania oprogramowania spotkasz si˛e jeszcze z kilkoma innymi rozszerzeniami. Moga˛ to być: • .pyc - plik zawiera tzw. bytecode czyli efekt kompilacji kodu źródłowego. Python tworzy te pliki podczas kompilacji jeżeli nic nie zmienimy w naszym kodzie źródłowym, wykorzystuje je bez potrzeby analizowania i kompilowania kodu ponownie. Od wersji 3.2 pliki .pyc znajduja˛ si˛e w specjalnym katalogu o nazwie __pycache__. • .pyd - Windowsowy plik ze skompilowanym kodem Pythona w formie biblioteki DLL. • .pyo - pliki zawieraja˛ obiekty wykorzystywane podczas kompilacji skryptów przy wykorzystaniu flagi -O. Sa˛ to obiekty zoptymalizowane. Od wersji 3.5 Pythona te pliki nie sa˛ już tworzone. • .pyw - Windowsowy plik z kodem źródłowym. Takie pliki odpalane sa˛ za pomoca˛ polecenia pythonw.exe • .pyx - Źródło cPythona, które b˛edzie przekonwertowane do C/C++ • .pyz - Python 3.5 wprowadził możliwość tworzenia Python ZIP Archive. Takie spakowane archiwum zawiera wszystkie pliki niezb˛edne do uruchomienia programu. Rozszerzenie dla obiektów tego typu jest .pyz. Do pakowania służy biblioteka zipapp. 4 Chapter 2. Wstep ˛ Python Workshop, Release 3f9e170, 2017-02-21 Instalacja Którego wersje˛ wybrać? Python kilka lat temu przeszedł drastyczna˛ transformacj˛e. Projekt Python 3 miał całkowicie zmienić sposób w jaki kompilator traktuje kod źródłowy. Dotychczas wszystkie ciagi ˛ znaków traktowane były jako ciagi ˛ ASCII. Od teraz miało to ulec zmianie a konto popularnego na całym świecie kodowania UTF-8. Wcześniej, aby skorzystać z takiego zachowania należało przed stringiem umieścić literk˛e “u”, np. u’Hello World!’ aby kompilator zrozumiał kodowanie. Niestety nie było to domyślne kodowanie i z tego powodu konieczne było ciagłe ˛ żonglowanie funkcjami .encode() i .decode(). Ponadto w nowym j˛ezyku Python 3 (czasami zwanym Python 3k [3k = 3000] aby pokazać, że drastycznie si˛e różni od wersji 2) scalono niektóre moduły biblioteki standardowej oraz zmieniono zachowanie niektórych funkcji w tym bardzo cz˛esto wykorzystywanej print(), która wcześniej była słowem kluczowym w j˛ezyku. Jeżeli rozpoczynasz nauk˛e programowania wybierz nowego Pythona 3. Jeżeli tworzysz nowy projekt wybierz podobnie. Na chwil˛e obecna˛ jedynym uzasadnieniem wyboru starszej wersji jest niekompatybilność niektórych bibliotek i projektów zewn˛etrznych. Na szcz˛eście z miesiaca ˛ na miesiac ˛ lista projektów “Python 3 compliant” wzrasta i wybór pozostaje coraz bardziej oczywisty. Ostatnia˛ wersja˛ gał˛ezi 2 jest 2.7. Wersja ta zawiera elementy i składni˛e ułatwiajace ˛ konwersj˛e programów do nowego środowiska i pozwala na pisanie aplikacji i skryptów, które powinny uruchomić si˛e zarówno przy wykorzystaniu interpretera python2 jak i python3. Wersja 2.7 jest ostatnia˛ z rodziny 2 i b˛eda˛ do niej wypuszczane jedynie poprawki bezpieczeństwa. Który interpreter? Sam Python jest tak naprawd˛e tylko specyfikacja˛ składni oraz wygladu ˛ biblioteki standardowej. Python ma obecnie kilka interpreterów z których najbardziej popularny jest cPython, który jest wydawany razem z nowa˛ wersja˛ specyfikacji j˛ezyka. cPython Domyślna˛ wersja˛ Pythona jest cPython. Jest to tzw. implementacja wzorcowa i to jej kompilator jest wydawany wraz ze specyfikacja˛ nowych funkcjonalności przy każdym wydaniu Python. Sam kompilator jest rozwijany w j˛ezyku C. cPython jest najbardziej popularna˛ dystrybucja˛ z wszystkich wydań. W poniższych materiałach to właśnie z tej wersji b˛edziemy korzystać. PyPy Bardzo ciekawy projekt napisania interpretera Pythona w... Pythonie. Kompilator dokonuje bardzo wielu niskopoziomowych optymalizacji dlatego ta wersja j˛ezyka jest wyjatkowo ˛ szybka. Niestety nie wszystkie biblioteki zewn˛etrzne sa˛ z nia˛ kompatybilne. Nie mniej projekt jest wcia˛ż aktywnie rozwijany przez bardzo pomysłowych programistów i stanowi solidna˛ alternatyw˛e dla cPythona. Niektóre programy przy wykorzystaniu PyPy potrafia˛ przyspieszyć kilkuset do kilkutysiac ˛ krotnie. IronPython Próba implementacji j˛ezyka Python wykorzystujac ˛ platform˛e .NET firmy Microsoft. Dzi˛eki temu j˛ezyk bardzo dobrze integruje si˛e z całym środowiskiem. 2.2. Instalacja 5 Python Workshop, Release 3f9e170, 2017-02-21 Jython Próba implementacji j˛ezyka Python wykorzystujac ˛ platform˛e wirtualnej maszyny JAVA (JVM). Projekt bardzo obiecujacy ˛ lecz niestety ostatnio słabo rozwijany. JVM stanowi bardzo dobra˛ platform˛e dobrze “wygrzana” ˛ oraz poznana˛ pod wzgl˛edem wydajnościowym jak i środowiska developerskiego. Inne W internecie jest dost˛epnych jeszcze wi˛ecej implementacji j˛ezyka. Niektóre projekty sa˛ jeszcze rozwijane, niektóre (Stackless Python) weszły w skład lub transformowały si˛e w wyżej wymienionych lub zostały zarzucone (Unleaden Swallow). Instalacja Windows Aby zainstalować Python na środowisku Windows należy pobrać instalator z python.org a nast˛epnie przejść przez wszystkie kroki kreatora. Po instalacji należy wylogować si˛e i zalogować ponownie aby odświeżyć zmienna˛ PATH. Po tym procesie w Windowsowej liście poleceń (cmd) b˛edzie dost˛epny program python. Ponadto wraz z instalacja˛ Pythona na Twoim komputerze zainstaluje si˛e edytor Idle, który w poczatkowej ˛ fazie nauki tworzenia oprogramowania powinien nam w zupełności wystarczyć. OS X Jeżeli posiadasz OS X to Python powinien być domyślnie zainstalowany na Twoim komputerze. Apple w najnowszych systemach operacyjnych standardowo dostarcza Pythona w wersji 2.7 i 2.6. Domyślnie po wpisaniu polecenia python uruchamiany jest 2.7. Aby zainstalować Pythona w wersji 3 możemy skorzystać z managera pakietów brew albo z tzw. macports. Osobiście polecam to pierwsze podejście. Brew dost˛epny jest za darmo i można pobrać go z internetu uruchamiajac ˛ polecenie ze strony Brew. Najpierw jednak konieczne b˛edzie zainstalowanie najnowszej wersji Xcode z AppStore. Brew powinien zrobić to za Ciebie. Sama instalacja brew sprowadza do uruchomienia polecenia wygladaj ˛ acego ˛ jak nast˛epujace: ˛ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" Nast˛epnie po instalacji: brew install python3 I już możemy cieszyć si˛e najnowszym Pythonem. Linux Niemalże wszystkie dystrybucje Linuxa posiadaja˛ zainstalowana˛ wersj˛e Pythona w wersji 2. Aby zainstalować trójk˛e użyj swojego managera pakietów apt-get, yum czy emerge czy rpm w zależności od dystrybucji. 6 Chapter 2. Wstep ˛ Python Workshop, Release 3f9e170, 2017-02-21 PYTHON_PATH Podstawy składni jezyka ˛ Ehlo World! W lekcjach programowania utarło si˛e, że zawsze zaczynamy od już przysłowiowego “Hello World”. Skrypty czy programy tego typu nie maja˛ na celu pokazania jak minimalna˛ ilościa˛ znaków da si˛e wyświetlić coś na ekranie, a sposób interakcji i przepływu programista-komputer. W Pythonie mamy możliwość wykorzystania interpretera REPL, przykład poniżej oraz stworzenia skryptu, który wykonamy z linii poleceń. $ python3 Python 3.5.1 (default, Dec 7 2015, 21:59:10) [GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.1.76)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> print('Hello World!') Hello World! Powyższy przykład ilustruje moment wpisania polecenia python, standardowy tekst informujacy ˛ o wersji i kompilacji j˛ezyka oraz znak zach˛ety >>> (ang. prompt). Polecenia wpisujemy po tym znaku a ich wynik wyświetla si˛e poniżej (i nie zawiera wci˛ecia). Dalej w materiałach b˛edziemy posługiwali si˛e już samym znakiem zach˛ety. Drugim sposobem jest stworzenie skryptu posiadajacego ˛ nast˛epujace ˛ linie. Ta metoda przydaje nam si˛e gdy nasze programy zaczna˛ rosnać ˛ na wi˛ecej niż jedna˛ dwie linijki. Warto zwrócić uwag˛e na pierwsza˛ lini˛e, na tzw. shebang #! i nast˛epujace ˛ po nim polecenie. To jest deklaracja programu, którego kod źródłowy znajduje si˛e poniżej. Linijka ta jest opcjonalna, ale dla zachowania poprawności i warto w naszych skryptach coś takiego zadeklarować. Już po pierwszej linii widzimy, że skrypt b˛edzie zinterpretowany jako kod źródłowy trzeciej wersji Pythona. #!/usr/bin/env python3 print('Hello World!') Wynik uruchomienia powyższego skryptu b˛edzie identyczny z efektem uzyskanym w REPL, tzn, na naszym ekranie ukaże si˛e napis Hello World. Dla wszystkich, którzy potrzebuja˛ wiedzieć jak wyglada ˛ najmniejszy kod, który wyświetli nam te słowa polecam poniższy kod. print('Hello World!') Deklaracje na poczatku ˛ pliku Deklaracja interpretera Jest to specjalny rodzaj komentarza który opisaliśmy pokrótce powyżej. Ten typ komentarza wyst˛epuje tylko w pierwszej linii programu i definiuje interpreter kodu źródłowego dla kodu poniżej. #!/usr/bin/env python3 2.3. Podstawy składni jezyka ˛ 7 Python Workshop, Release 3f9e170, 2017-02-21 Deklaracja kodowania znaków w pliku Jest to kolejny rodzaj specjalnego komentarza, który instruuje interpreter i jawnie wskazuje na sposób kodowania znaków w pliku z kodem źródłowym. W skryptach Pythona w wersji drugiej był obowiazkowy, ˛ jeżeli w kodzie lub komentarzach w pliku znajdowały si˛e znaki z poza zakresu ASCII, np. polskie znaki diakrytyczne a,˛ e˛ , ś, ć itp. # -*- coding: utf-8 -*- Informacja na temat modułu Pierwszy wielolinijkowy komentarz w pliku jest traktowany jako opis modułu. Może si˛e w nim znajdować np. licencja użytkowania programu, instrukcja jego obsługi itp. Bardzo ciekawym pomysłem jest również napisanie komentarza opisujacego ˛ parametry programów wykorzystujacego ˛ standard *unix takiego opisu. Dzi˛eki temu poza samym jednoznacznym opisem działania programu zgodnym z ogólnie przyj˛eta˛ konwencja˛ dostajemy możliwość wykorzystania modułu docopt do jego sparsowania i obsługi parametrów przekazywanych z linii poleceń. Docopt bierze opis z komentarza i parsuje zmienne zgodnie z instrukcja˛ czyniac ˛ niektóre elementy obligatoryjnymi, możliwymi do podania jedno- lub wielokrotnie itp. Samym opisem działania tego modułu zajmiemy si˛e w sekcji jemu poświ˛econej. Wciecia ˛ zamiast nawiasów klamrowych Jest to chyba najbardziej ciekawa rzecz w samym j˛ezyku. Autorzy specyfikacji zdecydowali si˛e na zastapienie ˛ nawiasów klamrowych wci˛eciami, czyli tzw. białymi spacjami (ang. whitespace). Jest to dość nietypowe rozwiazanie, ˛ które okazało si˛e bardzo rewolucyjne i niesamowicie podniosło czytelność kodu źródłowego. Sama idea spowodowała duża˛ polaryzacj˛e programistów. Jedni bardzo sobie chwala˛ to rozwiazanie, ˛ a inni przyzwyczajeni do j˛ezyków przypominajacych ˛ składnia˛ C sa˛ jej zaciekłymi wrogami. Osobiście jestem wielkim zwolennikiem takiego rozwiazania! ˛ >>> from __future__ import braces File "<stdin>", line 1 SyntaxError: not a chance Końce linii Pierwsza˛ rzecza˛ (poza znaczacymi ˛ wci˛eciami), która może zaskoczyć programistów przyzwyczajonych do składni C jest brak konieczności, a nawet zalecenie do niestawiania znaku średnika ; na końcu linii. Programy interpretowane sa˛ linia po linii. Linia kończy si˛e tam, gdzie ostatni znak polecenia. Python pozwala na stosowanie znaków końca linii zarówno znanych z systemów Windows (rn) jak i środowiska *nix (n). W tych materiałach b˛edziemy posługiwali si˛e znakiem n symbolizujacym ˛ koniec linii. Duck typing W j˛ezykach programowania można doszukać si˛e wielu systemów typowania. System typowania informuje kompilator o obiekcie oraz o jego zachowaniach. Ponadto niesie za soba˛ informacj˛e na temat ilości pami˛eci, która˛ trzeba dla takiego obiektu zarezerwować. Istnieje nawet cała gałaź ˛ zajmujaca ˛ si˛e systemami typów. Obecnie najcz˛eściej wykorzystywane j˛ezyki programowania dziela˛ si˛e na statycznie - silnie typowane (JAVA, C, C++ i pochodne) oraz dynamicznie - słabo typowane (Python, Ruby, PHP itp.). Oczywiście moga˛ znaleźć si˛e rozwiazania ˛ hybrydowe oraz z tzw. inrefencja˛ typów itp. 8 Chapter 2. Wstep ˛ Python Workshop, Release 3f9e170, 2017-02-21 W naszym przypadku skupmy si˛e na samym mechanizmie dynamicznego typowania. Określenie to oznacza, że j˛ezyk nie posiada typów zmiennych i obiektów, które jawnie trzeba deklarować. Inicjujac ˛ zmienna˛ nie musimy powiedzieć, że jest to int. Co wi˛ecej po chwili do tej zmiennej możemy przypisać dowolny obiekt, np. łańcuch znaków i kompilator nie powie nam złego słowa. Kompilator podczas działania oprogramowania niejawnie może zmienić typ obiektu i dokonać na nim konwersji. Wśród programistów popularne jest powiedzenie “jeżeli chodzi jak kaczka i kwacze jak kaczka, to musi być to kaczka”. Od tego powiedzenia wzi˛eła si˛e nazwa Duck typing. Określenie to jest wykorzystywane w stosunku do j˛ezyków, których typy obiektów rozpoznawane sa˛ po metodach, które można na nich wykonać. Nie zawsze takie zgadywanie jest celne i jednoznacznie i precyzyjnie określa typ. Może si˛e okazać, że obiekt np. Samochód posiada metody uruchom_silnik() i jedz_prosto() podobnie jak Motor. Jeden i drugi obiekt b˛edzie zachowywał si˛e podobnie. J˛ezyki wykorzystujace ˛ ten mechanizm wykorzystuja˛ specjalne metody porównawcze, które jednoznacznie daja˛ informacj˛e kompilatorowi czy dwa obiekty sa˛ równe. Sam mechanizm dynamicznego typowania jest dość kontrowersyjny, ze wzgl˛edu na możliwość bycia nieścisłym. W praktyce okazuje si˛e, że rozwój oprogramowania wykorzystujacego ˛ ten sposób jest dużo szybszy. Za to zwolennicy statycznego typowania, twierdza,˛ że projekty wykorzystujace ˛ duck typing sa˛ trudne w utrzymaniu po latach. Celem tego dokumentu nie jest udowadnianie wyższości jednego rozwiazania ˛ nad drugim. Zach˛ecam jednak do zapoznania si˛e z wykładem “The Unreasonable Effectiveness of Dynamic Typing for Practical Programs”, którego autorem jest “Robert Smallshire”. Wykład zamieszczonym został w serwisie InfoQ (http://www.infoq.com/presentations/dynamicstatic-typing). Wykład w ciekawy sposób dotyka problematyki porównania tych dwóch metod systemu typów. Wykład jest o tyle ciekawy, że bazuje na statystycznej analizie projektów umieszczonych na https://github.com a nie tylko bazuje na domysłach i flamewar jakie programiści lubia˛ prowadzić. Wszystko jest obiektem W Pythonie wszystkie rzeczy sa˛ obiektem. Każdy element posiada swoje metody, które możemy na nim uruchomić. W dalszej cz˛eści tych materiałów b˛edziemy korzystali z polecenia help() aby zobaczyć jakiego z jakiego typu obiektem mamy okazj˛e pracować oraz co możemy z nim zrobić. Komentarze Komentarze sa˛ wykorzystywane by podpowiedzieć programiście, który b˛edzie czytał kod źródłowy w przyszłości co dana funkcja, metoda lub po prostu kolejna linijka kodu robi. Jestem wielkim fanem pisania tak swoich programów, aby komentarze w kodzie były zb˛edne. Dobrego dzielenia aplikacji na mniejsze cz˛eści, właściwego stosowania whitespace’ów, precyzyjnego i opisowego ich nazywania. Komentarze moga˛ być bardzo przydatne, ale w wi˛ekszości sytuacji jeżeli potrzebujemy z nich skorzystać to znaczy, że logicznie źle rozplanowaliśmy układ naszego kodu. Ponadto komentarze maja˛ brzydka˛ właściwość szybkiego starzenia si˛e, tzn. kod ewoluuje, a komentarz opisuje zachowanie starej funkcji. Może to powodować dezinformacj˛e. Zakomentowany kod Bardzo cz˛esto spotykam si˛e z problemem zakomntowanego kodu. O ile komentarze opisujace ˛ działanie poszczególnych elementów sa˛ użyteczne to zakomentowany kod jest nieakceptowalny. Cz˛esto stosujemy ta˛ technik˛e by chwilowo wyłaczyć ˛ działanie jakiejś funkcjonalności. Jednakże niedopuszczalne jest commitowanie zmian zawierajacych ˛ zakomentowany kod. Kod taki bardzo cz˛esto jest już niedziałajacy ˛ i taki pozostanie na zawsze. Bardzo cz˛esto słysz˛e argument, że może kiedyś b˛edziemy chcieli powrócić do tego kodu i bez sensu b˛edzie go wymyślać i pisać na nowo. W dobie systemów kontroli wersji sytuacja ta nie b˛edzie stwarzała jakiegokolwiek problemu. Wystarczy przeglad˛ nać ˛ diffa (podglad ˛ różnicowy) pliku albo wykonać git blame i mamy dost˛ep do starego sposobu. Nieuruchamiajacy ˛ si˛e i niewywoływany kod nie powinien znaleźć si˛e w repozytorium. Kropka! 2.3. Podstawy składni jezyka ˛ 9 Python Workshop, Release 3f9e170, 2017-02-21 Komentowanie linii W Pythonie mamy kilka sposobów komentowania. Najprostszym z nich jest komentowanie całej linii poprzez wykorzystanie znaku zwanego “pound” lub “hash” #. Ciag ˛ znaków znajdujacych ˛ si˛e za # zostanie zignorowany przez kompilator. >>> #na ekranie otrzymamy: Hello World! ... print('Hello World!') Hello Wold! Tu możemy zaobserwować zachowanie, o którym wspominaliśmy troch˛e wcześniej, tzn. kontynuacja jest oznaczana przez znak zach˛ety trzech kropek .... Komentarze inline Kolejnym sposobem jest komentowanie inline tzn. w linijce. Tego typu komentarze stosuje si˛e aby wytłumaczyć zachowanie poszczególnych linii kodu. Choć kompilator dopuszcza ich stosowanie, to w ramach dobrych praktyk lepiej zastapić ˛ je komentarzami w linijce poprzedzajacej ˛ wywołanie. >>> print('Hello Wold!') #na ekranie otrzymamy: Hello World! Hello Wold! Komentarze wieloliniowe Komentarze wieloliniowe w Pythonie można robić na dwa sposoby poprzez wykorzystanie trzech znaków cudzysłowia: • pojedynczego ’’’, • podwójnego """. W jednym i drugim przypadku cudzysłowie podwójne lub pojedyncze b˛edzie oznaczało poczatek ˛ jak i koniec komentarza. Rodzaj cudzysłowiów nie ma znaczenia, ale utarło si˛e aby stosować podwójne ". W materiałach b˛edziemy korzystać właśnie z tej notacji. """ Tu jest treść komentarza, który obejmuje wiele linii W ramach dobrych praktyk, powinniśmy takim komentarzem opisać każda˛ z funkcji, aby narz˛ edzia takie jak np. ``help()`` wyświetlały ładne podpowiadanie działania. """ Sa˛ dwie szkoły tworzenia takich komentarzy. Jedna mówi, aby tekst pisać bezpośrednio po znaku cudzysłowia, a druga od nowej linijki. Jest to kwestia estetyki i czytelności komentarza. Virtualenv Tworzenie wirtualnego środowiska Wraz z wersja˛ Python 3.3 do j˛ezyka został dodany ten genialny moduł. Aplikacja ta odpowiada na problem zarzadzania ˛ zależnościami na Twojej maszynie. Dzi˛eki użyciu Virtualenv (po właczeniu ˛ jako standard zwany pyvenv. Mamy możliwość do tworzenia tzw. wirtualnych środowisk Pythona. Środowisko to zawiera w sobie plik wykonywalny j˛ezyka oraz wszystkie potrzebne biblioteki wewn˛etrzne i zewn˛etrzne. Takie środowiska możemy tworzyć per projekt i nie musimy martwić si˛e, że Projekt A wymaga np. Django w wersji 1.8 a Projekt B w 1.9. Tworzenie takiego środowiska jest bardzo łatwe i szybkie: 10 Chapter 2. Wstep ˛ Python Workshop, Release 3f9e170, 2017-02-21 pyvenv .virtualenv lub na Windowsie: python3 -m venv .virtualenv Aktywacja i korzystanie ze środowiska I po chwili w pojawi si˛e katalog .virtualenv ze środowiskiem. Nast˛epnie za każdym razem kiedy b˛edziesz chciał pracować wykorzystujac ˛ to środowisko b˛edzie konieczna jego aktywacja: source .virtualenv/bin/activate lub na Windowsie: .virtualenv\bin\activate.bat Pakiety i zależności Instalacja pakietów Każda instalacja pakietów oraz bibliotek wykona si˛e w środowisku. Skrypt który uruchomisz wykorzysta właśnie te wersje, które masz w nim zainstalowane. Aby zainstalować jakieś nowe paczki należy użyć polecenia pip. Od wersji Python 3.4 pip jest zainstalowany domyślnie. pip install pep8 lub na Windows: python -m pip install pep8 Lista zainstalowanych paczek Aby zobaczyć zainstalowane paczki, użyj polecenia pip freeze. Przekierowujac ˛ wynik tego polecenia do pliku requirements.txt stworzysz list˛e zależności wraz z wersjami, które sa˛ niezb˛edne dla uruchomienia Twojego programu. pip freeze > requirements.txt lub na Windows: python -m pip install pep8 Wi˛ecej na temat instalowania paczek, modularyzacji itp. znajdziesz w rozdziale tej ksia˛żki poświ˛econym temu tematowi. 2.4. Virtualenv 11 Python Workshop, Release 3f9e170, 2017-02-21 12 Chapter 2. Wstep ˛ CHAPTER 3 Podstawy Stałe, zmienne i typy danych Stałe i zmienne Deklarowanie zmiennych moja_zmienna = 10 moja_zmienna = 'przykladowy tekst' Deklarowanie stałych MOJA_STALA = 10 MOJA_STALA = ‘przykladowy tekst’ Różnica miedzy ˛ stałymi i zmiennymi Zasieg ˛ widoczności • globals() • locals() Numeryczne typy danych int - Liczba całkowita Jednym z najbardziej podstawowych typów danych jest int. int() jest funkcja˛ wbudowana,˛ która zamieni swój argument na liczb˛e całkowita.˛ float - Liczba zmiennoprzecinkowa float w Pythonie reprezentuje liczb˛e zmiennoprzecinkowa.˛ Ciekawa˛ własnościa˛ tego typu jest możliwość reprezentacji nieskończoności za pomoca˛ Infinity oraz minus nieskończoności -Infinity. Wi˛ecej szczegółów dost˛epnych jest w dokumentacji dla tego typu Podobnie jak pozostałe typy float() jest funkcja,˛ która konwertuje swój argument na liczb˛e zmiennoprzecinkowa.˛ 13 Python Workshop, Release 3f9e170, 2017-02-21 >>> float('+1.23') 1.23 >>> float(' -12345\n') -12345.0 >>> float('1e-003') 0.001 >>> float('+1E6') 1000000.0 >>> float('-Infinity') -inf complex - liczba zespolona complex reprezentuje typ liczby zespolonej posiadajacej ˛ cz˛eść rzeczywista˛ oraz urojona.˛ Należy zwrócić uwag˛e, że argument powinien być ciagiem ˛ znaków niezawierajacym ˛ spacji. W przeciwnym przypadku otrzymamy ValueError. >>> complex('1+2j') (1+2j) >>> complex('1 + 2j') Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: complex() arg is a malformed string Tekstowe typy danych str - Ciag ˛ znaków Obiekt typu str przechowuje łańcuch znaków. str() jest także funkcja,˛ która zwraca ciag ˛ znaków z argumentu. Niemutowalność Ważna˛ cecha˛ ciagów ˛ znakowych jest tzw. niemutowalność. Gdy wykonujemy operacj˛e na stringu tworzona jest jego nowa kopia. Różnica miedzy ˛ ‘a“ Python nie rozróżnia czy stosujemy pojedyncze znaki cudzysłowiu czy podwójne. Ważne jest aby wybrać jedna˛ konwencj˛e i si˛e jej konsekwentnie trzymać. Interpreter Pythona domyślnie stosuje pojedyncze znaki cudzysłowia, z tego powodu w tym materiale b˛edziemy trzymać si˛e tej konwencji. Operacje na stringach • strip(), lstrip(), rstrip() • join() • startswith() • title() 14 Chapter 3. Podstawy Python Workshop, Release 3f9e170, 2017-02-21 • replace() • Wycinanie cz˛eści stringów Konwersja stringów • bin() • hex() • oct() Logiczne typy danych bool - Wartość logiczna Obiekt typu bool może przyjać ˛ dwie wartości logiczne: • True • False Zwróć uwag˛e na wielkość liter! bool() to także funkcja wbudowana w j˛ezyk Python, która zwraca wartość logiczna˛ wyrażenia. None - Wartość pusta Złożone typy danych tuple - Krotka list - Lista set - Zbiór dict - Słownik Dobieranie sie˛ do wartości elementów [0] i .get(0) Rozszerzone typy danych Lista słowników Listy wielowymiarowe Drzewa Jak inicjować poszczególne typy? • dict() czy {} 3.1. Stałe, zmienne i typy danych 15 Python Workshop, Release 3f9e170, 2017-02-21 • list() czy [] • tuple() czy () • set() czy {} Instrukcje warunkowe if ... elif ... else if not 0 <= k <= n: raise ValueError("Sample larger than population") not, in, is switch statement? P˛etle Wybitnie użyteczne petla ˛ for while Funkcje Definiowanie funkcji def hello(): print('hello world') Konwencja nazewnicza funkcji • CamelCase? Nie?! Używanie _ w nazwach • Funkcje o nazwie zaczynajacej ˛ si˛e od _ przez konwencj˛e sa˛ traktowane jako prywatne (w Pythonie nie ma private/protected/public). • Funkcje o nazwie zaczynajacej ˛ si˛e od __ i kończacych ˛ si˛e na __ przez konwencj˛e sa˛ traktowane jako systemowe. • Nazwy opisowe funkcji Argumenty do funkcji >>> def dodaj(a, b): ... return a + b >>> dodaj(1, 2) 3 16 Chapter 3. Podstawy Python Workshop, Release 3f9e170, 2017-02-21 Argumenty nazwane >>> def dodaj(a, b): ... return a + b >>> dodaj(a=1, b=2) 3 Argumenty z wartościa˛ domyślna˛ >>> def hello(tekst='hello world'): ... print(tekst) >>> hello(tekst='ehlo') ehlo >>> hello() hello world Zwracanie wartości Zwracanie wartości prostych def foo1(): return True def foo2(): return None def foo3(): return 'bar' def foo4(): return [10, 20] def foo5(): return foo1 def foo6(): pass def foo7(): return 10, 20, 30, 5, 'a' def foo8(): return {'imie': 'Matt', 'nazwisko': 'Harasymczuk'} Zwracanie typów złożonych def foo9(): return [ {'imie': 'Matt', 'nazwisko': 'Harasymczuk'}, {'imie': 'Matt', 'nazwisko': 'Harasymczuk'}, {'imie': 'Matt', 'nazwisko': 'Harasymczuk'}] 3.4. Funkcje 17 Python Workshop, Release 3f9e170, 2017-02-21 Rozpakowywanie wartości zwracanych >>> napiece, natezenie, *args = foo7() >>> napiecie, *_ = foo7() >>> value, _ = function() >>> value, *args = function() Operator * i ** Argumenty *args, **kwargs def foo(a, b, *args, **kwargs): print(locals()) Przy wywołaniu funkcji foo(1, 2, **{'napiecie':10, 'natezenie': 20, 'moc': 3}) foo( 1, 2, napiecie=10, natezenie=20, moc=3) def bar(): return range(0, 5) jeden, dwa, *reszta = bar() print(jeden, dwa, reszta) def foobar(a, b, *args): print(locals()) foobar(1, 2, 5, 7) def foobar(a, b, **kwargs): print(locals()) foobar(1, 2, 5, 7) Przykładowe zastosowanie 18 Chapter 3. Podstawy Python Workshop, Release 3f9e170, 2017-02-21 class Osoba: first_name = 'Matt' last_name = 'Harasymczuk' def __str__(self): return '{first_name} {last_name}'.format(**self.__dict__) Funkcje wbudowane i słowa kluczowe Słowa kluczowe pass continue break return sorted range isinstance() __file__ __name__ if __name__ == '__main__': print('hello world') import logging log = logging.getLogger(__name__) 3.5. Funkcje wbudowane i słowa kluczowe 19 Python Workshop, Release 3f9e170, 2017-02-21 Wszystkie funkcje wbudowane abs() all() any() ascii() bin() bool() bytearray() bytes() callable() chr() classmethod() compile() complex() delattr() dict() dir() divmod() enumerate() eval() exec() filter() float() format() frozenset() getattr() globals() hasattr() hash() Built-in Functions help() hex() id() input() int() isinstance() issubclass() iter() len() list() locals() map() max() memoryview() min() next() object() oct() open() ord() pow() print() property() range() repr() reversed() round() set() setattr() slice() sorted() staticmethod() str() sum() super() tuple() type() vars() zip() __import__ Funkcje wbudowane min() max() len() input() Operatory Lista operatorów Operacja % ** \\ < += <= > >= == != is is not in not in 20 Znaczenie modulo (reszta) pot˛ega pow() dzielenie bez reszty mniejsze niż dodanie i przypisanie mniejsze lub równe wi˛eksze niż wi˛eksze lub równe równe różne obiekty sa˛ tożsame obiekty nie sa˛ tożsame obiekty sa˛ tożsame obiekty nie sa˛ tożsame Chapter 3. Podstawy Python Workshop, Release 3f9e170, 2017-02-21 Operacje na typach numerycznych Operacja x + y x - y x * y x / y x // y x % y -x +x abs(x) int(x) float(x) complex(re, im) divmod(x, y) pow(x, y) x ** y Rezultat suma x i y różnica x i y iloczyn x i y iloraz x i y podłoga z ilorazu x i y reszta z dzielenia x / y x negacja x bez zmiany wartość bezwzgl˛edna x x przekonwertowane do int x przekonwertowane do float liczba zespolona: re - cz˛eść rzeczywista im - cz˛eść urojona para (x // y, x % y) x podniesione do pot˛egi y x do pot˛egi y Kolejność operatorów • modulo • // i ** • przypisania i porównania • += • in i not in Pliki Konstrukcja with • Context manager Czytanie with open(FILENAME) as file: content = file.read() with open(FILENAME) as file: content = file.readlines() with open(FILENAME) as file: for line in file: print(line) 3.7. Pliki 21 Python Workshop, Release 3f9e170, 2017-02-21 Zapis with open(FILENAME, 'w') as file: file.write('foobar') with open(FILENAME, 'a') as file: file.write('foobar') Tryby odczytu i zapisu Character ’r’ ’w’ ’x’ ’a’ ’b’ ’t’ ’+’ ’U’ Meaning open for reading (default) open for writing, truncating the file first open for exclusive creation, failing if the file already exists open for writing, appending to the end of the file if it exists binary mode text mode (default) open a disk file for updating (reading and writing) universal newlines mode (deprecated) Obsługa wyjatków ˛ FILENAME = input('Podaj nazw˛ e pliku: ') try: with open(FILENAME, 'w') as file: content = file.read() print(content) except FileNotFoundError: print('File does not exists') except PermissionError: print('Brak uprawnien') Doctesty Niezwykle użytecznym sposobem komentowania sa˛ tzw. doctesty. W wielolinijkowym komentarzu wpisujemy sesj˛e z interpreterem a po uruchomieniu doctestów otrzymujemy informacj˛e czy nasza funkcja poprawnie si˛e wykonuje. Jest to bardzo proste narz˛edzie, które poza samym pokazaniem jak działa funkcja, jakie parametry przyjmuje i co zwraca daje możliwość weryfikacji poprawności działania kodu. W tych materiałach nieraz b˛edziemy korzystać z tego rozwiazania. ˛ def sumowanie_liczb(a, b): """Funkcja sumuje dwie liczby podane jako argumenty: >>> sumowanie_liczb(1, 2) 3 >>> sumowanie_liczb(-1, 1) 0 >>> sumowanie_liczb(0, 0) 22 Chapter 3. Podstawy Python Workshop, Release 3f9e170, 2017-02-21 0 """ return a + b Wykorzystujac ˛ taki zapis natychmiast widzimy co dzieje si˛e w danym rozwiazaniu. ˛ Doctesty bardzo przydaja˛ si˛e przede wszystkim do zastosowań wykorzystujacych ˛ wyrażenia regularne, których zrozumienie zapisu cz˛esto wymaga chwili zastanowienia. Print formatting Stary styl - %s • kolejnościowe • nazwane • typy: string, int, float • operatory na stringu Nowy styl - .format() • string • int • float • operatory na stringu • jako parametry do print("string", **args) f-strings - Python >= 3.6 • f’{variable}’ • f’{self.field}’ • f’{datetime:%Y-%m-%d %H:%M}’ Wiecej ˛ informacji • https://pyformat.info - Formatowanie stringów w Python Logowanie zdarzeń Poziomy logowania • Critical • Error • Warning 3.9. Print formatting 23 Python Workshop, Release 3f9e170, 2017-02-21 • Info • Debug Korzystanie z logging logging.critical('Bład ˛ krytyczny, kończ˛ e.') logging.error('Bład, ˛ ale kontynuuj˛ e.') logging.warning('Uwaga b˛ ed˛ e coś robił') logging.info('B˛ ed˛ e coś robił') logging.debug('Robi˛ e to tak') Konfiguracja logowania import logging logging.basicConfig(level=logging.DEBUG) logging.basicConfig(format='[%(asctime).19s] [%(levelname)s] %(message)s') 24 Chapter 3. Podstawy Python Workshop, Release 3f9e170, 2017-02-21 Konfiguracja formatowania logów Format args Description The tuple of arguments merged into msg to produce message, or a dict whose values are used for the merge (when there is only one argument, and it is a dictionary). You shouldn’t need to format this yourself. %(asctime)s Human-readable time when the LogRecord was created. By default this is of the form ‘2003-07-08 16:49:45,896’ (the numbers after the comma are millisecond portion of the time). %(created)f Time when the LogRecord was created (as returned by time.time). exc_info Exception tuple (à la sys.exc_info) or, if no exception has occurred, None. You shouldn’t need to format this yourself. %(filename)s Filename portion of pathname. %(funcName)s Name of function containing the logging call. %(levelname)sText logging level for the message (’DEBUG’, ’INFO’, ’WARNING’, ’ERROR’, ’CRITICAL’). %(levelno)s Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL). %(lineno)d Source line number where the logging call was issued (if available). %(module)s Module (name portion of filename). %(msecs)d Millisecond portion of the time when the LogRecord was created. %(message)s The logged message, computed as msg % args. This is set when Formatter.format is invoked. msg The format string passed in the original logging call. Merged with args to produce message, or an arbitrary object (see arbitrary-object-messages). You shouldn’t need to format this yourself. %(name)s Name of the logger used to log the call. %(pathname)s Full pathname of the source file where the logging call was issued (if available). %(process)d Process ID (if available). %(processName)s Process name (if available). %(relativeCreated)d Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded. stack_info Stack frame information (where available) from the bottom of the stack in the current thread, up to and including the stack frame of the logging call which resulted in the creation of this record. You shouldn’t need to format this yourself. %(thread)d Thread ID (if available). %(threadName)s Thread name (if available). Programowanie obiektowe Paradygmat Obiektowy Dziedziczenie Wielodziedziczenie Kompozycja Dziedziczenie czy kompozycja? class OtwieralneSzyby: def otworz_szyby(self): raise NotImplementedError 3.11. Programowanie obiektowe 25 Python Workshop, Release 3f9e170, 2017-02-21 class OtwieralnyDach: def otorz_dach(self): raise NotImplementedError class UmieTrabic: def zatrab(self): print('\bbiip') class Pojazd: kola = None class Samochod(Pojazd, UmieTrabic, OtwieralneSzyby): kola = 4 def wlacz_swiatla(self, *args, **kwargs): print('właczam ˛ światła') class Cabrio(Samochod, OtwieralnyDach): def wlacz_swiatla(self, *args, **kwargs): print('Podnieś obudow˛ e lamp') print('Puść muzyzk˛ e') super(Cabrio, self).wlacz_swiatla(*args, **kwargs) print('Zatrab') ˛ class Motor(Pojazd, UmieTrabic): kola = 2 c = Cabrio() c.wlacz_swiatla() Polimorfizm >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> >>> 26 class Pojazd: def zatrab(self): raise NotImplementedError class Motor(Pojazd): def zatrab(self): print('bip') class Samochod(Pojazd): def zatrab(self): print('biiiip') obj = Motor() Chapter 3. Podstawy Python Workshop, Release 3f9e170, 2017-02-21 >>> obj.zatrab() >>> >>> obj = Samochod() >>> obj.zatrab() Klasy abstrakcyjne Składnia Klasy Metody self Pola klasy Konstruktor super() @property i @x.setter class Cls: def __init__(self): self._x = None @property def x(self): """I'm the 'x' property.""" return self._x @x.setter def x(self, value): self._x = value @x.deleter def x(self): del self._x @staticmethod __str__() i __repr__() Metaclass Przeciażanie ˛ operatorów __eq__() __ne__() 3.11. Programowanie obiektowe 27 Python Workshop, Release 3f9e170, 2017-02-21 __lt__() __le__() __gt__() __ge__() Dobre praktyki Ask don’t tell Inicjalizacja parametrów Private, public? konwencja _ i __ Co powinno być w klasie a co nie? Klasa per plik? Serializacja pickle >>> import pickle >>> p = pickle.dumps(PYTHON) >>> print('Z Python do Pickle:', p) >>> pp = pickle.loads(p) >>> print('Z Pickle do Python:', pp) >>> osoba = pp[0] >>> print('Obiekt po konwersji:', osoba.nazwisko) json >>> import json >>> json.loads() Problem z rzutowaniem daty na JSON: >>> json.JSONEncoder.default = lambda self,obj: ('{:%Y-%m-%dT%H:%M:%S.%fZ}'.format(obj) if isinstance >>> json.dumps() csv 28 Chapter 3. Podstawy Python Workshop, Release 3f9e170, 2017-02-21 >>> import csv >>> with open('filename.csv') as csvfile: ... data = csv.DictReader(csvfile, delimiter=',', quotechar='"') ... ... for row in data: ... print(row['first_name'], row['last_name']) >>> import csv >>> data = [ ... {'first_name': 'Baked', 'last_name': 'Beans'}, ... {'first_name': 'Lovely', 'last_name': 'Spam'}, ... {'first_name': 'Wonderful', 'last_name': 'Spam'} ...] >>> with open('filename.csv', 'w') as csvfile: ... fieldnames = data[0].keys() ... writer = csv.DictWriter(csvfile, fieldnames=fieldnames, delimiter=',', quotechar='"', quoting= ... writer.writeheader() ... ... for row in data: ... writer.writerow(row) ... xml <execute> <command timeout="2">/bin/ls -la /etc/</command> <command>/bin/ls -l /home/ /tmp/</command> <command timeout="1">/bin/sleep 2</command> <command timeout="2">/bin/echo 'juz wstalem'</command> </execute> import logging import xml.etree.ElementTree import subprocess FILENAME = 'xml-execute-commands.xml' LOG_FORMAT = '[%(levelname)-5s] %(filename)s:%(lineno)s - %(msg).110s' logging.basicConfig(level=logging.INFO, format=LOG_FORMAT) log = logging.getLogger('code-execution') root = xml.etree.ElementTree.parse(FILENAME).getroot() def run(command, timeout=1): log.info('Executing command: %s' % command) with subprocess.Popen(command, stdout=subprocess.PIPE) as proc: try: output, errors = proc.communicate(timeout=timeout) except subprocess.TimeoutExpired: log.error('Timeout %s exceeded for command: %s' % (timeout, command)) return proc.kill() 3.12. Serializacja 29 Python Workshop, Release 3f9e170, 2017-02-21 if errors: log.error(errors) if output: # red = '\033[00;31m' # green = '\033[00;32m' # blue = '\033[00;36m' # white = '\033[00;39m' message = output.decode() log.debug('Output: {message}'.format(**locals())) return message for command in root.findall('./command'): cmd = command.text.split() timeout = float(command.get('timeout', 1)) run(cmd, timeout) xslt import io from lxml import etree XSLT = ''' <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <foo><xsl:value-of select="/a/b/text()" /></foo> </xsl:template> </xsl:stylesheet> ''' xslt_root = etree.XML(XSLT) transform = etree.XSLT(xslt_root) f = io.StringIO('<a><b>Text</b></a>') doc = etree.parse(f) result_tree = transform(doc) print(result_tree) 30 Chapter 3. Podstawy Python Workshop, Release 3f9e170, 2017-02-21 Wyjatki ˛ Po co sa˛ wyjatki? ˛ Najpopularniejsze wyjatki ˛ Nazwa wyjatku ˛ AttributeError ImportError IndexError KeyError KeyboardInterrupt NameError NotImplementedError RuntimeError SyntaxError IndentationError TypeError Opis Raised when an attribute reference (see Attribute references) or assignment fails. (When an object does not support attribute references or attribute assignments at all, TypeError is raised.) Raised when an import statement fails to find the module definition or when a from ... import fails to find a name that is to be imported. Raised when a sequence subscript is out of range. (Slice indices are silently truncated to fall in the allowed range; if an index is not an integer, TypeError is raised.) Raised when a mapping (dictionary) key is not found in the set of existing keys. Raised when the user hits the interrupt key (normally Control-C or Delete). During execution, a check for interrupts is made regularly. The exception inherits from BaseException so as to not be accidentally caught by code that catches Exception and thus prevent the interpreter from exiting. Raised when a local or global name is not found. This applies only to unqualified names. The associated value is an error message that includes the name that could not be found. This exception is derived from RuntimeError. In user defined base classes, abstract methods should raise this exception when they require derived classes to override the method. Raised when an error is detected that doesn’t fall in any of the other categories. The associated value is a string indicating what precisely went wrong. Raised when the parser encounters a syntax error. This may occur in an import statement, in a call to the built-in functions exec() or eval(), or when reading the initial script or standard input (also interactively). Base class for syntax errors related to incorrect indentation. This is a subclass of SyntaxError. Raised when an operation or function is applied to an object of inappropriate type. The associated value is a string giving details about the type mismatch. Przechwytywanie wyjatków ˛ • try • except • else • finally Hierarchia wyjatków ˛ BaseException +-- SystemExit +-- KeyboardInterrupt +-- GeneratorExit +-- Exception +-- StopIteration +-- StopAsyncIteration +-- ArithmeticError 3.13. Wyjatki ˛ 31 Python Workshop, Release 3f9e170, 2017-02-21 | | | +-+-+-+-+-+-| | +-+-| +-| | | | | | | | | | | | | | | +-+-| | +-| | +-+-+-| | | | +-- 32 +-- FloatingPointError +-- OverflowError +-- ZeroDivisionError AssertionError AttributeError BufferError EOFError ImportError LookupError +-- IndexError +-- KeyError MemoryError NameError +-- UnboundLocalError OSError +-- BlockingIOError +-- ChildProcessError +-- ConnectionError | +-- BrokenPipeError | +-- ConnectionAbortedError | +-- ConnectionRefusedError | +-- ConnectionResetError +-- FileExistsError +-- FileNotFoundError +-- InterruptedError +-- IsADirectoryError +-- NotADirectoryError +-- PermissionError +-- ProcessLookupError +-- TimeoutError ReferenceError RuntimeError +-- NotImplementedError +-- RecursionError SyntaxError +-- IndentationError +-- TabError SystemError TypeError ValueError +-- UnicodeError +-- UnicodeDecodeError +-- UnicodeEncodeError +-- UnicodeTranslateError Warning +-- DeprecationWarning +-- PendingDeprecationWarning +-- RuntimeWarning +-- SyntaxWarning +-- UserWarning +-- FutureWarning +-- ImportWarning +-- UnicodeWarning +-- BytesWarning +-- ResourceWarning Chapter 3. Podstawy Python Workshop, Release 3f9e170, 2017-02-21 Dobre praktyki PEP20 - Zen of Python import this The Zen of Python • Beautiful is better than ugly. • Explicit is better than implicit. • Simple is better than complex. • Complex is better than complicated. • Flat is better than nested. • Sparse is better than dense. • Readability counts. • Special cases aren’t special enough to break the rules. • Although practicality beats purity. • Errors should never pass silently. • Unless explicitly silenced. • In the face of ambiguity, refuse the temptation to guess. • There should be one– and preferably only one –obvious way to do it. • Although that way may not be obvious at first unless you’re Dutch. • Now is better than never. • Although never is often better than right now. • If the implementation is hard to explain, it’s a bad idea. • If the implementation is easy to explain, it may be a good idea. • Namespaces are one honking great idea – let’s do more of those! Zen Pythona • Pi˛ekne jest lepsze niż brzydkie. • Wyrażone wprost jest lepsze niż domniemane. • Proste jest lepsze niż złożone. • Złożone jest lepsze niż skomplikowane. • Płaskie jest lepsze niż wielopoziomowe. • Rzadkie jest lepsze niż g˛este. • Czytelność si˛e liczy. • Sytuacje wyjatkowe ˛ nie sa˛ na tyle wyjatkowe, ˛ aby łamać reguły. 3.14. Dobre praktyki 33 Python Workshop, Release 3f9e170, 2017-02-21 • Choć praktyczność przeważa nad konsekwencja.˛ • Bł˛edy zawsze powinny być sygnalizowane. • Chyba że zostana˛ celowo ukryte. • W razie niejasności powstrzymaj pokus˛e zgadywania. • Powinien być jeden – i najlepiej tylko jeden – oczywisty sposób na zrobienie danej rzeczy. • Choć ten sposób może nie być oczywisty jeśli nie jest si˛e Holendrem. • Teraz jest lepsze niż nigdy. • Chociaż nigdy jest cz˛esto lepsze niż natychmiast. • Jeśli rozwiazanie ˛ jest trudno wyjaśnić, to jest ono złym pomysłem. • Jeśli rozwiazanie ˛ jest łatwo wyjaśnić, to może ono być dobrym pomysłem. • Przestrzenie nazw to jeden z niesamowicie genialnych pomysłów – miejmy ich wi˛ecej! PEP8 Wciecia ˛ Tak: # Aligned with opening delimiter. foo = long_function_name(var_one, var_two, var_three, var_four) # More indentation included to distinguish this from the rest. def long_function_name( var_one, var_two, var_three, var_four): print(var_one) # Hanging indents should add a level. foo = long_function_name( var_one, var_two, var_three, var_four) Nie: # Arguments on first line forbidden when not using vertical alignment. foo = long_function_name(var_one, var_two, var_three, var_four) # Further indentation required as indentation is not distinguishable. def long_function_name( var_one, var_two, var_three, var_four): print(var_one) Zamykanie nawiasów 34 Chapter 3. Podstawy Python Workshop, Release 3f9e170, 2017-02-21 my_list = [ 1, 2, 3, 4, 5, 6, ] result = some_function_that_takes_arguments( 'a', 'b', 'c', 'd', 'e', 'f', ) Lub: my_list = [ 1, 2, 3, 4, 5, 6, ] result = some_function_that_takes_arguments( 'a', 'b', 'c', 'd', 'e', 'f', ) Tabulacje i czy spacje? Gł˛ebokość wci˛eć równa czterem spacjom. Długość linii To jest dość kontrowersyjna klauzula mówiaca ˛ o tym, że długość linii powinna być nie dłuższa niż 79 znaków. Przy obecnych wielkich szerokokatnych ˛ monitorach jest to dość ucia˛żliwe. Jednakże należy przestrzegać konwencji. Linie możemy łamać poprzez stawianie znaku ukośnika \ na końcu: with open('/path/to/some/file/you/want/to/read') as file_1, \ open('/path/to/some/file/being/written', 'w') as file_2: file_2.write(file_1.read()) class Rectangle(Blob): def __init__(self, width, height, color='black', emphasis=None, highlight=0): if (width == 0 and height == 0 and color == 'red' and emphasis == 'strong' or highlight > 100): raise ValueError("sorry, you lose") if width == 0 and height == 0 and (color == 'red' or emphasis is None): raise ValueError("I don't think so -- values are %s, %s" % (width, height)) Blob.__init__(self, width, height, color, emphasis, highlight) 3.14. Dobre praktyki 35 Python Workshop, Release 3f9e170, 2017-02-21 Puste linie Kodowanie plików Przy Pythonie 3 kodownaie plików powinno być w UTF-8. Importy Importy powinny być poukładane alfabetycznie w grupach. Na górze importy z bibliotek standardowych Pythona. Nast˛epnie linia przerwy i zewn˛etrzne zależności. Znów linia przerwy i zależności wewnatrz ˛ Twoich aplikacji. Każdy z importów powinien być w osobnej linii. Tak: import os import sys Nie: import sys, os Ale można: from subprocess import Popen, PIPE Cudzysłowia Python interpretuje cudzysłowia pojedyncze i podwójne tak samo. Ważne jest aby wybrać jeden sposób i konsekwentnie si˛e go trzymać w całej aplikacji. Białe spacje w wyrażeniach Tak: spam(ham[1], {eggs: 2}) ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:] ham[lower:upper], ham[lower:upper:], ham[lower::step] ham[lower+offset : upper+offset] ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)] ham[lower + offset : upper + offset] spam(1) dct['key'] = lst[index] x = 1 y = 2 long_variable = 3 i = i + 1 submitted += 1 x = x*2 - 1 hypot2 = x*x + y*y c = (a+b) * (a-b) 36 Chapter 3. Podstawy Python Workshop, Release 3f9e170, 2017-02-21 def complex(real, imag=0.0): return magic(r=real, i=imag) def def def def munge(input: AnyStr): munge(sep: AnyStr = None): munge() -> AnyStr: munge(input: AnyStr, sep: AnyStr = None, limit=1000): if foo == 'blah': do_blah_thing() do_one() do_two() do_three() Nie: spam( ham[ 1 ], { eggs: 2 } ) ham[lower + offset:upper + offset] ham[1: 9], ham[1 :9], ham[1:9 :3] ham[lower : : upper] ham[ : upper] spam (1) dct ['key'] = lst [index] x = 1 y = 2 long_variable = 3 i=i+1 submitted +=1 x = x * 2 - 1 hypot2 = x * x + y * y c = (a + b) * (a - b) def complex(real, imag = 0.0): return magic(r = real, i = imag) def munge(input: AnyStr=None): def munge(input:AnyStr): def munge(input: AnyStr)->PosInt: if foo == 'blah': do_blah_thing() do_one(); do_two(); do_three() if foo == 'blah': do_blah_thing() else: do_non_blah_thing() try: something() finally: cleanup() do_one(); do_two(); do_three(long, argument, list, like, this) if foo == 'blah': one(); two(); three() 3.14. Dobre praktyki 37 Python Workshop, Release 3f9e170, 2017-02-21 Komentarze Google style comments Konwencje nazewnicze • zmienne • STALE • NazwyKlas • nazwy_metod() i nazwy_funkcji() • nazwymodulow nazwy_modulow • self • cls Używanie __ i _ w nazwach Konstrukcje warunkowe Yes: if foo is not None: No: if not foo is None: Zwracanie z funkcji Tak: def foo(x): if x >= 0: return math.sqrt(x) else: return None def bar(x): if x < 0: return None return math.sqrt(x) Nie: def foo(x): if x >= 0: return math.sqrt(x) def bar(x): if x < 0: return return math.sqrt(x) 38 Chapter 3. Podstawy Python Workshop, Release 3f9e170, 2017-02-21 Sprawdzanie warunków Tak: if not seq: if seq: if greeting: Nie: if len(seq) if not len(seq) if greeting == True: if greeting is True: Korzystanie z help(), dir() i object.__dict__ Kilka przykaładów z praktyki html.append(’<tag>’) Magic number i Magic string Passowords Wczytywanie konfiguracji programów Wersjonowanie API Zadania Powielanie napisów Nazwa skryptu bin/zadanie1-powielanie-napisow.py Uruchamianie python bin/zadanie1-powielanie-napisow.py Zadanie 1 Napisz program, który wczyta od użytkownika pewien napis, a nast˛epnie wyświetli 30 kopii tego napisu, każda w osobnej linii. Zadanie 2 Napisz trzy wersje tego programu: • wykorzystujac ˛ range() • wykorzystujac ˛ p˛etl˛e while • wykorzystujac ˛ właściwości mnożenia stringów Zadanie 3 Napisz doctest do takiej funkcji. Podpowiedź • print(’ciag znakow’ * 30) 3.15. Zadania 39 Python Workshop, Release 3f9e170, 2017-02-21 Parzystość Nazwa skryptu bin/zadanie2-parzystosc.py Uruchamianie python bin/zadanie2-parzystosc.py Zadanie • napisz program, który wczyta od użytkownika ciag ˛ znaków • zweryfikuje czy wprowadzony ciag ˛ jest liczba˛ (int lub float) • sprawdzi czy jest to liczba parzysta, czy nieparzysta Podpowiedź • Liczba parzysta, to taka, która po podzieleniu przez dwa nie ma reszty • Użyj dzielenia modulo % lub divmod() • Zwróć uwag˛e, że operator % działa modulo tylko na int oraz na float. Przy str ma zupełnie inne znaczenie. Liczby całkowite Nazwa skryptu bin/zadanie3-calkowite.py Uruchamianie python bin/zadanie3-calkowite.py Zadanie Napisz program, który wczyta od użytkownika liczb˛e i wyświetli informacj˛e, czy jest to liczba całkowita, czy niecałkowita. Podpowiedź Liczba całkowita to taka, której cz˛eść dziesi˛etna nie wyst˛epuje (int) lub jest równa zero float. Dzienniczek ucznia Nazwa skryptu bin/oceny.py Uruchamianie python bin/oceny.py Zadanie Napisz program, który wczytuje od użytkownika kolejne oceny i: • sprawdza czy wprowadzona ocena jest na liście dopuszczalnych na wydziale ocen • jeżeli ocena jest na liście dopuszczalnych na wydziale ocen, dodaje ja˛ do dzienniczka • jeżeli wpisano cyfr˛e nie znjadujac ˛ a˛ si˛e na liście dopuszczalnych ocen, wyświetl informacj˛e i zakończ wpisywanie • wyświetla wyliczona˛ dla dzienniczka ocen średnia˛ arytmetyczna˛ • jeżeli wciśni˛eto sam Enter, oznacza to koniec wpisywania do dzienniczka • wykorzystaj moduł statistics do wyliczania średniej Warunek • Zastosuj akademicka˛ skal˛e ocen [2, 3, 3.5, 4, 4.5, 5] Podpowiedź • dla ułatwienia wszystkie oceny moga˛ być typu float • len() sum() 40 Chapter 3. Podstawy Python Workshop, Release 3f9e170, 2017-02-21 • in • import statistics statistics.mean() Przeliczenia trygonometryczne Nazwa skryptu bin/trygonometria.py Uruchamianie python bin/trygonometria.py Zadanie Napisz program, który wczyta od użytkownika wielkość kata ˛ w stopniach i wyświetli wartość czterech podstawowych funkcji trygonometrycznych (sin, cos, tg, ctg) o ile dla danego kata ˛ jest to możliwe. Wyrazy Nazwa skryptu bin/podzial-wyrazow.py Uruchamianie python bin/podzial-wyrazow.py Zadanie Napisz program, który wczyta od użytkownika pewien tekst, a nast˛epnie podzieli go na zdania (zakładamy, że jednoznacznie kropka rozdziela zdania) i dla każdego zdania wyświetli ile jest w nim wyrazów (zakładamy, że spacja oddziela wyrazy w zdaniu). Podpowiedź • str.split() • len() Lotto Nazwa skryptu bin/lotto.py Uruchamianie python bin/lotto.py Zadanie Napisz program, który wyświetli 6 losowych i nie powtarzajacych ˛ si˛e liczb z zakresu od 1 do 49. Podpowiedź • random.randrange() • random.sample() Pytania • Czym sa liczby pseudolosowe? • Czy da si˛e stworzyć program czysto losowy? • Dlaczego? Przeliczanie temperatury Nazwa skryptu bin/temperatura.py Uruchamianie python bin/temperatura.py 3.15. Zadania 41 Python Workshop, Release 3f9e170, 2017-02-21 Zadanie Woda zamarza przy 32 stopniach Fahrenheita, a wrze przy 212 stopniach Fahrenheita. Napisz program, który wyświetli tabel˛e przeliczeń stopni Celsjusza na stopnie Fahrenheita w zakresie od –20 do +40 stopni Celsjusza (co 5 stopni). Pami˛etaj o wyświetlaniu znaku plus/minus przy temperaturze. Oczywiście napisz testy do rozwiazania. ˛ Podpowiedź • Fahrenheit to Celsius: (°F - 32) / 1.8 = °C • Celsius to Fahrenheit: (°C * 1.8) + 32 = °F Pole trójkata ˛ Nazwa skryptu bin/pole-trojkata.py Uruchamianie python bin/pole-trojkata.py Zadanie Napisz program, który obliczy pole trójkata, ˛ pod warunkiem że użytkownik poda wysokość i długość podstawy tego trójkata. ˛ Uwzgl˛ednij, że wysokość i długość podstawy moga˛ być liczbami niecałkowitymi. Wykorzystaj doctest do przetestowania funckji. Wyliczanie średniej dla parametrów Nazwa skryptu bin/srednia.py Uruchamianie python bin/srednia.py Zadanie 1 Zdefiniuj funkcj˛e avg(), która dla dowolnej liczby parametrów zwróci ich średnia˛ arytmetyczna˛ (lub 0 dla 0 parametrów). Zadanie 2 Dowolna liczba parametrów podanych z linii poleceń. Podpowiedź • getopt • argparse • docopt Uruchamianie python bin/srednia.py 5 10 100 32 -90 27.5 Konwersja liczby na zapis słowny Nazwa skryptu bin/konwersja-liczby.py Uruchamianie python bin/konwersja-liczby.py Zadanie 1 Napisz program “numer.py‘‘”, który zamieni wprowadzony przez użytkownika ciag ˛ cyfr na form˛e tekstowa: ˛ • znaki nie b˛edace ˛ cyframi maja˛ być ignorowane • konwertujemy cyfry, nie liczby, a zatem: * 911 to “dziewi˛eć jeden jeden” * 1100 to “jeden jeden zero zero” Zadanie 2 Napisz program, który przekonwertuje liczb˛e na zapis słowny, np.: 42 Chapter 3. Podstawy Python Workshop, Release 3f9e170, 2017-02-21 >>> int_to_str(999) 'dziewiećset dziewi˛ ećdziesiat ˛ dziewi˛ eć' >>> int_to_str(127.32) 'sto dwadzieścia siedem i trzydzieści dwa setne' Zakres • 6 cyfr przed przecinkiem • 5 cyfr po przecinku Zadanie 3 Napisz testy sprawdzajace ˛ przypadki brzegowe. Rzymskie Nazwa skryptu bin/rzymskie.py Uruchamianie python bin/rzymskie.py Zadanie 1 Napisz program, który przeliczy wprowadzona˛ liczb˛e rzymska˛ na jej postać dziesi˛etna.˛ Zadanie 2 Zrób druga˛ funkcj˛e, która dokona procesu odwrotnego. map(), filter() i lambda Nazwa skryptu bin/funkcyjne.py Uruchamianie python bin/funkcyjne.py Zadanie 1 Używajac ˛ generatora zbuduj list˛e zawierajac ˛ a˛ wszystkie liczby podzielne przez 3 z zakresu od 1 do 33. Zadanie 2 • Używajac ˛ funkcji filter() usuń z niej wszystkie liczby parzyste • Używajac ˛ wyrażenia lambda i funkcji map() podnieś wszystkie elementy tak otrzymanej listy do sześcianu • Odpowiednio używajac ˛ funkcji sum() i len() oblicz średnia˛ arytmetyczna˛ z elementów tak otrzymanej listy. Zawartość pliku Nazwa skryptu bin/zawartosc-pliku.py Uruchamianie python bin/zawartosc-pliku.py Zadanie 1 Napisz program, który wyświetli na ekranie zawartość pliku o nazwie podanej przez użytkownika. Zadanie 2 Dopisz obsług˛e wyjatków ˛ dla braku uprawnień oraz tego że plik nie istnieje. Ksiażka ˛ adresowa Nazwa skryptu bin/ksiazka-adresowa.py Uruchamianie python bin/ksiazka-adresowa.py 3.15. Zadania 43 Python Workshop, Release 3f9e170, 2017-02-21 Zadanie Napisz ksia˛żk˛e adresowa,˛ która b˛edzie zapisywała dane do pliku w formacie json. Każdy z użytkowników jest reprezentowany przez: • imi˛e • nazwisko • telefon • adres • ulica • miasto • kod_pocztowy • wojewodztwo • panstwo Wszystkie dane w ksia˛żce musza˛ być reprezentowane przez typy proste. Zadanie 2 Bardzo cz˛esto wykorzystywanym typem pliku jest CSV, czyli wartości oddzielone przecinkami. Zamień format pliku na ten typ. Zrób tak, aby dane trafiły do odpowiednich kolumn nawet po przesortowaniu. Użyj csv.DictWriter(). Wszystkie pola musza˛ być zawsze w cudzysłowiach i oddzielone średnikami. Zadanie 3 Zmodyfikuj aby można było wpisywać wiele adresów. Zadanie 4 Zmodyfikuj program aby wykorzystywał klasy do reprezentowania wpisów w ksia˛żce. Które podejście jest lepsze? Zadanie 5 Teraz wykorzystaj plik bazy danych sqlite aby trzymać informacje w tabeli. Które podejście jest lepsze? Zadanie 6 Wykorzystaj Django do stworzenia takiego modelu i wygeneruj panel administracyjny. Trudne? Pytanie • Które podejście było najłatwiejsze? • W jakim formacie najlepiej przechowywać dane? • Które podejście jest najlepsze dla innych programistów, a które dla użytkowników? Zbalansowanie nawiasów Nazwa skryptu bin/zbalansowanie-nawiasow.py Uruchamianie python bin/zbalansowanie-nawiasow.py Zadanie 1 Napisz kod który sprawdzi zbalansowanie nawiasów, tzn. czy ilość otwieranych nawiasów jest równa ilości nawiasów zamykanych. Zwórć uwag˛e, że moga˛ być cztery typy nawiasów: • okragłe: ˛ (i) • kwadratowe: [ i ] • klamrowe { i } • trójkatne ˛ <i> Zadanie 2 Rozbuduj poniższy zestaw testów i napisz funkcjonalność. 44 Chapter 3. Podstawy Python Workshop, Release 3f9e170, 2017-02-21 >>> dane = "() [] () ([]()[])" >>> zbalansowanie_nawiasow(a) True >>> dane = "( (] ([)]" >>> zbalansowanie_nawiasow(a) False Zadanie 3 Spróbuj użyć rekurencji. 3.15. Zadania 45 Python Workshop, Release 3f9e170, 2017-02-21 46 Chapter 3. Podstawy CHAPTER 4 Średniozaawansowany Biblioteka standardowa datetime import datetime datetime.datetime.now() datetime.date.today() datetime.datetime.now() - datetime.timedelta(hours=3) datetime.datetime.now().replace(tzinfo=datetime.timezone.utc) time os import os os.path os.walk os.path.join os.path.abspath os.path.dirname sys import sys sys.path sys.path.append sys.platform warnings 47 Python Workshop, Release 3f9e170, 2017-02-21 import warnings warnings.warn('Wersja API jest już nieaktualna', PendingDeprecationWarning) pprint from pprint import pprint data = [ {'first_name': 'Baked', 'last_name': 'Beans'}, {'first_name': 'Lovely', 'last_name': 'Spam'}, {'first_name': 'Wonderful', 'last_name': 'Spam'} ] pprint(data) csv import csv csv.DictReader() csv.DictWriter() memoize json import json json.loads() json.dumps() sqlite re import re re.search() re.findall() re.match() re.compile() 48 Chapter 4. Średniozaawansowany Python Workshop, Release 3f9e170, 2017-02-21 httplib urllib socket tempfile io import io io.StringIO functools itertools math import math math.sin() math.cos() math.tan() math.pi statistics import statistics statistics.avg() statistics.mean() statistics.stdev() random import random random.sample() random.random() subprocess import subprocess subprocess.Popen() 4.1. Biblioteka standardowa 49 Python Workshop, Release 3f9e170, 2017-02-21 doctest import doctest doctest.testmod() Collections Name namedtuple() deque ChainMap Counter OrderedDict defaultdict UserDict UserList UserString Description factory function for creating tuple subclasses with named fields list-like container with fast appends and pops on either end dict-like class for creating a single view of multiple mappings dict subclass for counting hashable objects dict subclass that remembers the order entries were added dict subclass that calls a factory function to supply missing values wrapper around dictionary objects for easier dict subclassing wrapper around list objects for easier list subclassing wrapper around string objects for easier string subclassing Biblioteki zewnetrzne ˛ Do zastosowań naukowych num.py sci.py pandas pybrain Wspierajacych ˛ programowanie sieciowe Standard WSGI requests >>> import requests >>> >>> >>> >>> requests.put('http://httpbin.org/put', data = {'key':'value'}) requests.delete('http://httpbin.org/delete') requests.head('http://httpbin.org/get') requests.options('http://httpbin.org/get') >>> payload = {'key1': 'value1', 'key2': 'value2'} >>> r = requests.get('http://httpbin.org/get', params=payload) >>> print(r.url) http://httpbin.org/get?key2=value2&key1=value1 >>> payload = {'key1': 'value1', 'key2': ['value2', 'value3']} 50 Chapter 4. Średniozaawansowany Python Workshop, Release 3f9e170, 2017-02-21 >>> r = requests.get('http://httpbin.org/get', params=payload) >>> print(r.url) http://httpbin.org/get?key1=value1&key2=value2&key2=value3 >>> import requests >>> r = requests.get('https://api.github.com/user', auth=('user', 'pass')) >>> r.status_code 200 >>> r.headers['content-type'] 'application/json; charset=utf8' >>> r.encoding 'utf-8' >>> r.text u'{"type":"User"...' >>> r.json() {u'private_gists': 419, u'total_private_repos': 77, ...} >>> url = 'https://api.github.com/some/endpoint' >>> headers = {'user-agent': 'my-app/0.0.1'} >>> r = requests.get(url, headers=headers) >>> payload = {'key1': 'value1', 'key2': 'value2'} >>> r = requests.post("http://httpbin.org/post", data=payload) >>> print(r.text) { ... "form": { "key2": "value2", "key1": "value1" }, ... } >>> r = requests.head('http://github.com', allow_redirects=True) >>> r.url 'https://github.com/' >>> r.history [<Response [301]>] >>> import json >>> url = 'https://api.github.com/some/endpoint' >>> payload = {'some': 'data'} >>> r = requests.post(url, data=json.dumps(payload)) >>> url = 'https://api.github.com/some/endpoint' >>> payload = {'some': 'data'} >>> r = requests.post(url, json=payload) • http://docs.python-requests.org/en/master/user/quickstart/#json-response-content • http://docs.python-requests.org/en/master/dev/contributing/#kenneth-reitz-s-code-style 4.2. Biblioteki zewnetrzne ˛ 51 Python Workshop, Release 3f9e170, 2017-02-21 suds Google App Engine django flask webapp2 tornado atlassian-python-api fabric BeautifulSoup Bazy danych pyMySQL psycopg2 pymongo SQLAlchemy Inne py2app docopt Jinja2 pytz ldap3 import datetime import time from pprint import pprint from ldap3 import Server, Connection, SEARCH_SCOPE_WHOLE_SUBTREE USER = "myusername" PASS = "mypassword" BASEDN = "OU=Users,DC=local" SERVER = Server("127.0.0.1", port=389) ATTRIBUTES = ['mail', 'pwdLastSet'] 52 Chapter 4. Średniozaawansowany Python Workshop, Release 3f9e170, 2017-02-21 def construct_filter(wintimestamp): return """(& (objectCategory=Person) (objectCategory=User) (userAccountControl=512) (pwdLastSet<={wintimestamp}) (mail=*) )""".format(wintimestamp=wintimestamp) def search(filter): with Connection(SERVER, user=USER, password=PASS) as c: c.search(BASEDN, filter, SEARCH_SCOPE_WHOLE_SUBTREE, attributes=ATTRIBUTES) return [record['attributes'] for record in c.response] def datetime_to_mstimestamp(date): """ Active Direcotry has different approach to create timestamp than Unix. Here's a function to convert the Unix timestamp to the AD one. >>> datetime_to_mstimestamp(datetime.datetime(2000, 1, 1, 0, 0)) 125911548000000000 """ timestamp = int(time.mktime(date.timetuple())) magic_number = 116444736000000000 return timestamp * 10000000 + magic_number def mstimestamp_to_datetime(mstimestamp): """ Active Direcotry has different approach to create timestamp than Unix. Here's a function to convert AD timestamp to the Unix one. >>> mstimestamp_to_datetime(130567328471235643) datetime.datetime(2014, 10, 2, 16, 14, 7, 123563) """ magic_number = 11644473600 return datetime.datetime.fromtimestamp(mstimestamp / 10000000 - magic_number) def month_ago(date): """ >>> month_ago(datetime.datetime(2000, 1, 31, 0, 0)) datetime.datetime(2000, 1, 1, 0, 0) """ return date - datetime.timedelta(days=30) def print_users_with_expiring_password(): now = datetime.datetime.now() expiration_date = month_ago(now) wintimestamp = datetime_to_mstimestamp(expiration_date) older_than_month_ago = construct_filter(wintimestamp) for user in search(older_than_month_ago): user['pwdLastSet'] = mstimestamp_to_datetime(int(user['pwdLastSet'][0])) pprint(user) 4.2. Biblioteki zewnetrzne ˛ 53 Python Workshop, Release 3f9e170, 2017-02-21 if __name__ == "__main__": print_users_with_expiring_password() Parametry linii poleceń argparse • https://docs.python.org/3/library/argparse.html#the-add-argument-method ArgumentParser.add_argument(name or flags...[, action][, nargs][, const][, default][, type][, choices Define how a single command-line argument should be parsed. Each parameter has its own more detailed description below, but in short they are: • name or flags - Either a name or a list of option strings, e.g. foo or -f, –foo. • action - The basic type of action to be taken when this argument is encountered at the command line. • nargs - The number of command-line arguments that should be consumed. • const - A constant value required by some action and nargs selections. • default - The value produced if the argument is absent from the command line. • type - The type to which the command-line argument should be converted. • choices - A container of the allowable values for the argument. • required - Whether or not the command-line option may be omitted (optionals only). • help - A brief description of what the argument does. • metavar - A name for the argument in usage messages. • dest - The name of the attribute to be added to the object returned by parse_args(). import argparse parser = argparse.ArgumentParser( prog='PROGRAM NAME', description='A foo that bars', epilog="And that's how you'd foo a bar") parser.add_argument('--sum', dest='accumulate', action='store_const', const=sum, default=max, help='sum the integers (default: find the max)') parser.add_argument('--foo', nargs='?', help='foo help') parser.add_argument('--bar', nargs='+', help='bar help') parser.add_argument('--foobar', nargs='*', default=[1, 2, 3], help='BAR!') parser.add_argument('--integers', metavar='int', type=int, choices=range(10), nargs='+', help='an integer in the range 0..9') parser.add_argument('--bar', nargs='?', type=int, default=42, help='the bar to %(prog)s (default: %(default)s)') parser.add_argument('--move', choices=['rock', 'paper', 'scissors']) 54 Chapter 4. Średniozaawansowany Python Workshop, Release 3f9e170, 2017-02-21 parser.add_argument('--length', default='10', type=int, required=True) parser.add_argument('--width', default=10.5, type=int, help='foo the bars before frobbling') parser.add_argument('--input', default='input.csv', type=argparse.FileType('r')) parser.add_argument('--output', default='output.c', type=argparse.FileType('w')) script = parser.parse_args() try: script = parser.parse_args() except SystemExit: pass Uruchamianie poleceń import subprocess import shlex cmd = 'ls -la' with subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE) as proc: ret = proc.stdout.read() print(ret) Timeout dla wykonywania poleceń • subprocess.run() - New in Python 3.5 import subprocess cmd = ['ping', 'www.google.com'] try: subprocess.run(cmd, timeout=5) except subprocess.TimeoutExpired: print('process ran too long') Parsowanie i sanityzacja argumentów >>> import shlex >>> import subprocess >>> command_line = input() /bin/vikings -input eggs.txt -output "spam spam.txt" -cmd "echo '$MONEY'" >>> args = shlex.split(command_line) >>> print(args) ['/bin/vikings', '-input', 'eggs.txt', '-output', 'spam spam.txt', '-cmd', "echo '$MONEY'"] >>> p = subprocess.Popen(args) # Success! 4.3. Parametry linii poleceń 55 Python Workshop, Release 3f9e170, 2017-02-21 Modularyzacja, wersjonowanie i dystrybucja Modularyzacja Plik __init__.py Linia if __name__ == ’__main__’ Importowanie wzgledne ˛ from . import * __all__ Konwencja nazewnicza - main.py Tworzenie paczek setup.py import sys from setuptools import find_packages from setuptools import setup assert sys.version_info >= (3, 4), 'Python 3.4+ required.' setup( name='atlassian-python-api', description='Python Atlassian REST API Wrapper', long_description='Python Atlassian REST API Wrapper', license='Apache License 2.0', version='0.14.0', download_url='https://github.com/MattAgile/atlassian-python-api', author='Matt Harasymczuk', author_email='[email protected]', url='http://mattagile.com/', packages=find_packages(), package_data={'': ['LICENSE', 'README.rst'], 'atlassian': ['*.py']}, package_dir={'atlassian': 'atlassian'}, include_package_data=True, zip_safe=False, install_requires=['requests==2.7.0'], platforms='Platform Independent', classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Web Environment', 'Intended Audience :: Developers', 'Intended Audience :: System Administrators', 'License :: OSI Approved :: Apache Software License', 'Natural Language :: English', 'Operating System :: OS Independent', 'Operating System :: POSIX', 56 Chapter 4. Średniozaawansowany Python Workshop, Release 3f9e170, 2017-02-21 'Operating System :: MacOS :: MacOS X', 'Operating System :: Microsoft :: Windows', 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.0', 'Programming Language :: Python :: 3.1', 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Topic :: Internet', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Libraries :: Application Frameworks'] ) setup.cfg [pep8] max-line-length = 939 ignore = E402,W391 python setup.py sdist upload Instalacja i korzystanie z zewnetrznych ˛ bibliotek pip search pip install pip install -r requirements.txt requirements.txt a setup.py wheel distutils i setuptools Przyszłość paczkowania i dystrybucji • https://www.youtube.com/watch?v=jOiAp3wtx18 • https://www.youtube.com/watch?v=Oc9khbXBes8 4.4. Modularyzacja, wersjonowanie i dystrybucja 57 Python Workshop, Release 3f9e170, 2017-02-21 Wyrażenia regularne Konstruowanie wyrażeń Wyciaganie ˛ parametrów (zmiennych) Najcze˛ ściej wykorzystywane funkcje match() search() findall() i finditer() compile() Greedy search Testy Doctest def km_na_metry(ile): """ >>> km_na_metry(1) 1000 >>> km_na_metry(0) 0 >>> km_na_metry(-1) Traceback (most recent call last): ... ValueError >>> km_na_metry('adas') Traceback (most recent call last): ... TypeError """ return ile * 1000 if __name__ == "__main__": import doctest doctest.testmod() MINIMALNA_TEMPERATURA = -273.15 def przelicz_celsius_na_kelvin(temperatura): """ >>> przelicz_celsius_na_kelvin(1) 274.15 >>> przelicz_celsius_na_kelvin(0) 58 Chapter 4. Średniozaawansowany Python Workshop, Release 3f9e170, 2017-02-21 273.15 >>> przelicz_celsius_na_kelvin(-300) Traceback (most recent call last): ... ValueError: Nie może być mniejsze niż minimalna temperatura >>> przelicz_celsius_na_kelvin('jeden') Traceback (most recent call last): ... ValueError: Temperatura musi być float >>> przelicz_celsius_na_kelvin([1.0, 1, 0]) Traceback (most recent call last): ... TypeError: Nie obsługiwany typ argumentu """ try: temperatura = float(temperatura) except ValueError: raise ValueError('Temperatura musi być float') except TypeError: raise TypeError('Nie obsługiwany typ argumentu') if temperatura < MINIMALNA_TEMPERATURA: raise ValueError('Nie może być mniejsze niż minimalna temperatura') else: return temperatura - MINIMALNA_TEMPERATURA Unit Test import unittest class Prostokat: def __init__(self, a, b): self.a = float(a) self.b = float(b) if self.a <= 0 or self.b <= 0: raise ValueError('Dlugosc bokow musi byc liczba naturalna') def pole(self): return self.a * self.b def obwod(self): return (self.a + self.b) * 2 def __str__(self): return 'Prostokat(a=%s, b=%s)' % (self.a, self.b) class ProstokatTest(unittest.TestCase): def setUp(self): self.prostokat = Prostokat(a=5, b=10) 4.6. Testy 59 Python Workshop, Release 3f9e170, 2017-02-21 def test_obliczania_pola(self): self.assertEqual(self.prostokat.pole(), 50) def test_obliczania_obwodu(self): self.assertEqual(self.prostokat.obwod(), 30) def test_ustawienia_bokow(self): with self.assertRaises(TypeError): Prostokat(a=0) with self.assertRaises(TypeError): Prostokat(b=0) def test_dlugosci_bokow(self): with self.assertRaises(ValueError): Prostokat(a=-1, b=-2) def test_prostokat_to_string(self): self.assertEqual(str(self.prostokat), 'Prostokat(a=5.0, b=10.0)') if __name__ == '__main__': unittest.main() selenium Mock Stub Tworzenie dokumentacji Format reStructuredText Po co? Paragrafy Nagłówki Odnośniki Obrazki i media Specjalne wstawki TODO Listy 60 Chapter 4. Średniozaawansowany Python Workshop, Release 3f9e170, 2017-02-21 Tabele reStructuredText vs. Markdown Sphinx Generowanie dokumentacji Buildery make html make singlehtml 4.7. Tworzenie dokumentacji 61 Python Workshop, Release 3f9e170, 2017-02-21 toctree Django Co to jest Django? Architektura aplikacji Django Modele Widoki Panel admina Dokumentacja Widoki generyczne Localization Sygnały Migracje schematów bazy danych Management Commands ORM Skrypty z Django Projektowanie GUI Biblioteka Tkinter • http://www.tkdocs.com/tutorial/index.html #!/usr/bin/env python3 from tkinter import * from tkinter import messagebox class Application(Frame): def say_hi(self): print("hi there, everyone!") def create_hi_button(self): self.hi_there = Button(self) self.hi_there["text"] = "Hello", self.hi_there["command"] = self.say_hi 62 Chapter 4. Średniozaawansowany Python Workshop, Release 3f9e170, 2017-02-21 self.hi_there.pack({"side": "left"}) def create_quit_button(self): self.QUIT = Button(self) self.QUIT["text"] = "QUIT" self.QUIT["command"] = self.quit self.QUIT.pack({"side": "left"}) def create_yesno_button(self): self.yesno = Button(self) self.yesno['text'] = 'Ask me a question' self.yesno['fg'] = 'white' self.yesno['command'] = self.show_yesno_screen self.yesno.pack({'side': 'right'}) def show_yesno_screen(self): messagebox.askyesno( message='Do you like it?', icon='question', title='Hi there!') def create_widgets(self): self.create_quit_button() self.create_hi_button() self.create_yesno_button() def __init__(self, master=None): self.frame = Frame.__init__(self, master) self.pack() self.create_widgets() root = Tk() app = Application(master=root) app.mainloop() root.destroy() #!/usr/bin/env python3 from tkinter import * from tkinter import ttk def print_hello(): print('Hello World!') root = Tk() content = ttk.Frame(root, padding=(3, 3, 12, 12)) frame = ttk.Frame(content, borderwidth=5, relief="sunken", width=200, height=100) namelbl = ttk.Label(content, text="Name") name = ttk.Entry(content) onevar = BooleanVar() twovar = BooleanVar() threevar = BooleanVar() 4.9. Projektowanie GUI 63 Python Workshop, Release 3f9e170, 2017-02-21 onevar.set(True) twovar.set(False) threevar.set(True) one = ttk.Checkbutton(content, text="One", variable=onevar, onvalue=True) two = ttk.Checkbutton(content, text="Two", variable=twovar, onvalue=True) three = ttk.Checkbutton(content, text="Three", variable=threevar, onvalue=True) ok = ttk.Button(content, text="Okay") cancel = ttk.Button(content, text="Cancel") ok['command'] = print_hello content.grid(column=0, row=0, sticky=(N, S, E, W)) frame.grid(column=0, row=0, columnspan=3, rowspan=2, sticky=(N, S, E, W)) namelbl.grid(column=3, row=0, columnspan=2, sticky=(N, W), padx=5) name.grid(column=3, row=1, columnspan=2, sticky=(N, E, W), pady=5, padx=5) one.grid(column=0, row=3) two.grid(column=1, row=3) three.grid(column=2, row=3) ok.grid(column=3, row=3) cancel.grid(column=4, row=3) root.columnconfigure(0, weight=1) root.rowconfigure(0, weight=1) content.columnconfigure(0, weight=3) content.columnconfigure(1, weight=3) content.columnconfigure(2, weight=3) content.columnconfigure(3, weight=1) content.columnconfigure(4, weight=1) content.rowconfigure(1, weight=1) root.mainloop() #!/usr/bin/env python3 from tkinter import * from tkinter import ttk root = Tk() l = Listbox(root, height=5) l.grid(column=0, row=0, sticky=(N,W,E,S)) s = ttk.Scrollbar(root, orient=VERTICAL, command=l.yview) s.grid(column=1, row=0, sticky=(N,S)) l['yscrollcommand'] = s.set ttk.Sizegrip().grid(column=1, row=1, sticky=(S,E)) root.grid_columnconfigure(0, weight=1) root.grid_rowconfigure(0, weight=1) for i in range(1, 101): l.insert('end', 'Line %d of 100' % i) 64 Chapter 4. Średniozaawansowany Python Workshop, Release 3f9e170, 2017-02-21 root.mainloop() Introspekcja Pola obiektu class Address: def __init__(self, host, port): self.host = host self.port = port addr = Address(host='127.0.0.1', port=1337) a = addr.__dict__ print('Listowanie za pomoca __dict__:\n{}\n\n'.format(a)) a = [x for x in dir(addr) if not x.startswith('__')] print('Listowanie pól klasy:\n{}\n\n'.format(a)) a = vars(addr) print('Listowanie za pomoca vars():\n{}\n\n'.format(a)) Metody obiektu class Address: def __init__(self, host, port): self.host = host self.port = port addr = Address(host='127.0.0.1', port=1337) a = dir(addr) print('Listowanie za pomoca˛ dir():\n"{}\n\n"'.format(a)) 4.10. Introspekcja 65 Python Workshop, Release 3f9e170, 2017-02-21 66 Chapter 4. Średniozaawansowany CHAPTER 5 Zaawansowany Generatory i list comprehension List comprehension • wykonywane natychmiast [x*x for x in range(0, 30) if x % 2] Generator expressions • lazy evaluation (x*x for x in range(0, 30) if x % 2) Operator yield osoby_w_klasie = {'username': {'username': {'username': {'username': ] [ 'wykladowca1', 'czy_wykladowca': True}, 'uczen1', 'czy_wykladowca': False}, 'uczen2', 'czy_wykladowca': False}, 'uczen3', 'czy_wykladowca': False}, def uczestnicy_kursu(osoby): def jest_wykladowca(user): if user['czy_wykladowca']: return True else: return False for osoba in osoby: if not osoba['czy_wykladowca']: yield { 'wykladowcy': jest_wykladowca, 'uczestnicy': [x for x in osoby if not x['czy_wykladowca']], 'wszystkie_username': [x['username'] for x in osoby] } 67 Python Workshop, Release 3f9e170, 2017-02-21 uczestnicy_kursu = [osoba.get('username') for osoba in osoby_w_klasie if not osoba['czy_wykladowca']] pprint(uczestnicy_kursu) Iteratory Czym jest iterator? • __next__() • raise StopIteration Iterowanie po obiektach Iterowanie po stringu for znak in 'python': print(znak) Iterowanie po list(), dict(), set(), tuple() for liczba in [1, 2, 3, 4]: print(liczba) for key, value in [(0, 0), (1, 1), (1, 2)]: print('%s -> %s' % (key, value)) slownik = {'x': 1, 'y': 2} for key in slownik: print(slownik.get(key)) for key, value in slownik.items(): print(key, value) Własny iterator class ListaFigurGeometrycznych: lista = [] aktualny_elemtent = 0 def __iter__(self): return self def push(self, figura): self.lista.append(figura) def next(self): self.aktualny_elemtent += 1 return self.lista[self.aktualny_elemtent] 68 Chapter 5. Zaawansowany Python Workshop, Release 3f9e170, 2017-02-21 prostokaty = ListaFigurGeometrycznych() prostokaty.push('kwadrat', 'prostokat') for figura in prostokaty: print(figura) System Operacyjny eval sys.platform sys.exit() subprocess Kolejki, watki ˛ i procesy Kolejki Queue PriorityQueue __all__ = [’Empty’, ‘Full’, ‘Queue’, ‘PriorityQueue’, ‘LifoQueue’] Watki ˛ a procesy Watki ˛ Tworzenie watków ˛ from threading import Timer def hello(): print("hello, world") t = Timer(5.0, hello) t.start() print('hej') Synchronizacja watków ˛ 5.3. System Operacyjny 69 Python Workshop, Release 3f9e170, 2017-02-21 import queue import threading import time exitFlag = 0 class myThread (threading.Thread): def __init__(self, threadID, name, q): threading.Thread.__init__(self) self.threadID = threadID self.name = name self.q = q def run(self): print("Starting %s" % self.name) process_data(self.name, self.q) print("Exiting %s" % self.name) def process_data(threadName, q): while not exitFlag: queueLock.acquire() if not workQueue.empty(): data = q.get() queueLock.release() print("%s processing %s" % (threadName, data)) else: queueLock.release() time.sleep(1) threadList = ["Thread-1", "Thread-2", "Thread-3"] nameList = ["One", "Two", "Three", "Four", "Five"] queueLock = threading.Lock() workQueue = queue.Queue(10) threads = [] threadID = 1 # Create new threads for tName in threadList: thread = myThread(threadID, tName, workQueue) thread.start() threads.append(thread) threadID += 1 # Fill the queue queueLock.acquire() for word in nameList: workQueue.put(word) queueLock.release() 70 Chapter 5. Zaawansowany Python Workshop, Release 3f9e170, 2017-02-21 # Wait for queue to empty while not workQueue.empty(): pass # Notify threads it's time to exit exitFlag = 1 # Wait for all threads to complete for t in threads: t.join() print("Exiting Main Thread") Zamykanie watków ˛ Workery import queue import logging import threading kolejka = queue.Queue() class Worker(threading.Thread): daemon = True def run(self): while True: # Remove and return an item from the queue. job = kolejka.get() # Execute work logging.warning('Will do the work: %s' % job) # Indicate that a formerly enqueued task is complete. kolejka.task_done() def spawn_workers(number_of_workers): for i in range(number_of_workers): Worker().start() if __name__ == '__main__': spawn_workers(3) # Zapełnij kolejk˛ e for todo in ['ping', 'ls -la', 'echo "hello world"', 'cat /etc/passwd']: kolejka.put(todo) # wait to complete all tasks kolejka.join() 5.4. Kolejki, watki ˛ i procesy 71 Python Workshop, Release 3f9e170, 2017-02-21 Procesy Tworzenie procesów Synchronizacja procesów IPC - komunikacja miedzyprocesowa ˛ figury.py class Prostokat: def __init__(self, a, b): self.a = float(a) self.b = float(b) def pole(self): return self.a * self.b def obwod(self): return (self.a + self.b) * 2 def __str__(self): return 'Prostokat(a=%s, b=%s)' % (self.a, self.b) processes-client.py from multiprocessing.connection import Client import logging import pickle from .figury import Prostokat rectangle = Prostokat(a=5, b=10) rect = pickle.dumps(rectangle) address = ('localhost', 6000) conn = Client(address, authkey=b'secret password') logging.warning('Sending objects') conn.send([rect, 'a', 2.5, None, int, sum]) logging.warning('Sending close') conn.send('close') conn.close() processes-listener.py from multiprocessing.connection import Listener import logging import pickle from .figury import Prostokat address = ('localhost', 6000) # family is deduced to be 'AF_INET' logging.warning('Listening on %s:%s' % address) 72 Chapter 5. Zaawansowany Python Workshop, Release 3f9e170, 2017-02-21 listener = Listener(address, authkey=b'secret password') conn = listener.accept() logging.warning('connection accepted from %s %s' % listener.last_accepted) while True: msg = conn.recv() logging.warning('Received: %s' % msg) if msg == 'close': conn.close() break else: # do something with msg prostokat = pickle.loads(msg[0]) logging.warning('Prostokat %s' % prostokat) print('Pole: %s' % prostokat.pole()) listener.close() Zamykanie procesów Programowanie funkcyjne lambda def czy_parzysta(x): if x % 2 == 0: return True else: return False parzyste = filter(czy_parzysta, liczby) foo = lambda x: x*x print(foo(10)) liczby = [1, 2, 3, 4] parzyste = filter(lambda x: x % 2 == 0, liczby) closure def f(x): def g(y): return x + y return g 5.5. Programowanie funkcyjne 73 Python Workshop, Release 3f9e170, 2017-02-21 decorator • Modify arguments • Modify returned value • Do things before call • Do things after call • Avoid calling • Modify global state • Metadata def my_decorator(f): def wrapper(*args, **kwargs): return f(*args, **kwargs) return wrapper # usage @my_decorator def func(x): return x import os import logging def if_file_exists(function): def check(filename): if os.path.exists(filename): function(filename) else: logging.error('File "%(filename)s" does not exists, will not execute!', locals()) return check @if_file_exists def print_file(filename): with open(filename) as file: content = file.read() print(content) if __name__ == '__main__': print_file('/etc/passwd') print_file('/tmp/passwd') 74 Chapter 5. Zaawansowany Python Workshop, Release 3f9e170, 2017-02-21 złożenia funkcji map() lista = [1, 2, 3] def inkrementuj(y): return 1 + y map(inkrementuj, lista) map(lambda y: 1 + y, l) zip() >>> x = [1, 2, 3] >>> y = [4, 5, 6] >>> zipped = zip(x, y) >>> list(zipped) [(1, 4), (2, 5), (3, 6)] >>> # unzip >>> x2, y2 = zip(*zip(x, y)) >>> x == list(x2) and y == list(y2) True filter() OSOBY = [ {'imie': {'imie': {'imie': {'imie': ] 'Matt', 'wiek': 10}, 'Angelika', 'wiek': 18}, 'Mateusz', 'wiek': 21}, 'Tadeusz', 'wiek': 35}, def osoba_pelnoletnia(osoba): if osoba['wiek'] >= 18: return True else: return False dorosli = filter(osoba_pelnoletnia, OSOBY) print(list(dorosli)) all() any() Programowanie sieciowe Socket 5.6. Programowanie sieciowe 75 Python Workshop, Release 3f9e170, 2017-02-21 Otwieranie połacze ˛ ń Nasłuchiwanie Przekazywanie informacji Prosty serwer HTTP httplib urllib smtp HTML Scrapping • BeautifulSoup Wzorce projektowe • Wzorce kreacyjne • Wzorce strukturalne • Wzorce czynnosciowe Wzorce kreacyjne Izolacja reguł tworzenia obiektow od reguł okreslajacych sposob uzywania obiektow (oddzielenie w kodzie programu kodu tworzacego obiekty od kodu, ktory uzywa obiekty) – klasy typu „Control” 1. Budowniczy - Builder - Sposob tworzenia złozonych obiektow 2. Fabrykaabstrakcyjna – AbstractFactory - Rodziny obiektow 3. Metodawytwórcza – FactoryMethod - Podklasa tworzonego obiektu 4. Prototyp - Prototype - Typ klasy tworzonego obiektu 5. Singleton - Jedna kopia obiektu C Extensions C Types #include <stdio.h> void ehlo() { printf("Ehlo World"); } void greeting(char *name) { 76 Chapter 5. Zaawansowany Python Workshop, Release 3f9e170, 2017-02-21 printf("Ehlo %s!\n", name); } void number(int num) { printf("My number %d\n", num); } int myint(int num) { return num; } gcc -fPIC -c -o hello-ctypes.o hello-ctypes.c -I/usr/local/Cellar/python3/3.5.2/Frameworks/Python.fra gcc -shared hello-ctypes.o -o hello-ctypes.so import ctypes ehlo = ctypes.CDLL('hello-ctypes.so') ehlo.ehlo() ehlo.greeting.argtypes = [ctypes.c_char_p] name = ctypes.create_string_buffer('Matt'.encode()) ehlo.greeting(name) ehlo.number(10) print(dir(ehlo)) i = ehlo.myint(15) print(i) C Modules Python 3 #include <Python.h> /* Implementation */ static PyObject* say_hello(PyObject* self, PyObject* args) { const char* name; if (!PyArg_ParseTuple(args, "s", &name)) return NULL; printf("Hello %s!\n", name); Py_RETURN_NONE; } static PyObject* version(PyObject* self) { return Py_BuildValue("s", "Version 1.0"); } /* Python Binding Definitions */ 5.8. C Extensions 77 Python Workshop, Release 3f9e170, 2017-02-21 static PyMethodDef HelloMethods[] = { {"say_hello", say_hello, METH_VARARGS, "Greet somebody."}, {"version"}, (PyCFunction)version, METH_NOARGS, "returns the version"}, {NULL, NULL, 0, NULL} }; static struct PyModuleDef hello = { PyModuleDef_HEAD_INIT, "hello", /* name of module */ "", /* module documentation, may be NULL */ -1, /* size of per-interpreter state of the module, or -1 if HelloMethods }; PyMODINIT_FUNC PyInit_hello(void) { return PyModule_Create(&hello); } Python 2 #include <Python.h> /* Implementation */ static PyObject* say_hello(PyObject* self, PyObject* args) { const char* name; if (!PyArg_ParseTuple(args, "s", &name)) return NULL; printf("Hello %s!\n", name); Py_RETURN_NONE; } static PyObject* version(PyObject* self) { return Py_BuildValue("s", "Version 1.0"); } /* Python Binding Definitions */ static PyMethodDef HelloMethods[] = { {"say_hello", say_hello, METH_VARARGS, "Greet somebody."}, {"version"}, (PyCFunction)version, METH_NOARGS, "returns the version"}, {NULL, NULL, 0, NULL} }; PyMODINIT_FUNC inithello(void) { (void) Py_InitModule("hello", HelloMethods); } 78 Chapter 5. Zaawansowany Python Workshop, Release 3f9e170, 2017-02-21 setup.py import sys from distutils.core import setup, Extension if sys.version_info >= (3,): print('Building for Python 3') module = Extension('hello', sources = ['hello-py3.c']) elif sys.version_info >= (2,): print('Building for Python 2') module = Extension('hello', sources=['hello-py2.c']) else: print('Unsupported Python version') sys.exit(1) setup( name = 'hello', version='1.0', description = 'Ehlo World!', ext_modules = [module]) python setup.py build cd build/lib* python import hello hello.say_hello('Matt') Zadania REST API Używajac ˛ biblioteki standardowej w Pythonie zaciagnij ˛ informacje o repozytoriach użytkownika Django na https://github.com • w przegladarce ˛ internetowej wygeneruj w swoim profilu token https://github.com/settings/tokens • Nast˛epnie z przegladnij ˛ list˛e z poziomu Pythona i znajdź URL dla repozytorium django. "name": "django", "full_name": "django/django", # wyszukaj "commits_url": ??? • Przegladnij ˛ to repozytorium i jego list˛e commitów. • Podaj dat˛e i opis ostatniego commita • Znajdź numery ID ticketów (Fixed #...) z issue trackera, które zostały rozwiazane ˛ w ostatnim miesiacu ˛ • Spróbuj skorzystać zamiast biblioteki standardowej z pakietu requests https://api.github.com/ GET /orgs/django/repos GET /repos/dajngo/django/commits 5.9. Zadania 79 Python Workshop, Release 3f9e170, 2017-02-21 curl https://api.github.com/orgs/django/repos >>> auth = b'username:token' >>> headers={ ... 'Authorization': 'Basic {}'.format(base64.b64encode(auth).decode('ascii')), ... 'User-Agent': 'Python HTTP', ...} # ... >>> body = resp.read().decode() >>> data = json.loads(body) Generatory vs. Przetwarzanie Listy Napisz program, który wczyta plik /etc/passwd, a nast˛epnie: • przefiltruje linie, tak aby nie zawierały komentarzy (zaczynajace ˛ si˛e od #) • przefiltruje linie, aby wyciagn ˛ ać ˛ konta systemowe - użytkowników, którzy maja˛ UID (trzecie pole) mniejsze niż 1000 • zwróci list˛e loginów takich użytkowników • Zaimplementuj rozwiazanie ˛ wykorzystujac ˛ zwykła˛ funkcj˛e. • Zaimplementuj rozwiazanie ˛ wykorzystujac ˛ generator i słówko kluczowe yield. • Porównaj wyniki jednego i drugiego rozwiazania ˛ przez użycie sys.getsizeof() Wielowatkowo ˛ ść • Stwórz kolejk˛e queue do której dodasz różne polecenia systemowe do wykonania, np. /etc/’, ’/bin/echo "test"’, ’/bin/sleep 2’]. [’/bin/ls • Nast˛epnie przygotuj trzy watki ˛ workerów, które b˛eda˛ wykonywały polecenia z kolejki. • Watki ˛ powinny być uruchamiane jako subprocess w systemie operacyjnym z timeoutem równym PROCESSING_TIMEOUT = 2.0 sekundy • Ilość poleceń może si˛e zwi˛ekszać w miar˛e wykonywania zadania. • Watki ˛ powinny być uśpione za pomoca˛ Timer przez 5.0 sekund, a nast˛epnie ruszyć do roboty. • Watki ˛ maja˛ być uruchomione w tle (ang. daemon) • Użyj logowania za pomoca˛ biblioteki logging tak aby przy wyświetlaniu wyników widoczny był identyfikator procesu i watku ˛ • Napisz testy do workerów i kolejki Podpowiedź import subprocess import shlex cmd = 'ls -la' with Popen(shlex.split(cmd), stdout=PIPE) as proc: log.write(proc.stdout.read()) 80 Chapter 5. Zaawansowany Python Workshop, Release 3f9e170, 2017-02-21 Mini Botnet Stwórz program, który otworzy socket na porcie na localhoście podanym przez użytkownika z linii poleceń (wykorzystaj argparse) i b˛edzie nasłuchiwał połaczeń. ˛ Zweryfikuj za pomoca˛ telnet albo netcat czy program odpowiada. Nast˛epnie napisz w pythonie klienta, który b˛edzie wysyłał polecenia do tamtego programu. Uwaga, nigdy nie rób tego na produkcji bez tzw. sanityzacji parametrów, np. lista zaufanych hostów, możliwe polecenia! • zrób aby przetwarzanie requestów było nieblokujace, ˛ tzn. otwieraj watek ˛ dla każdego zapytania • program wykona polecenie za pomoca˛ eval, które przyszło z zapytania • wykonaj polecenie w systemie operacyjnym i zwróć klientowi odpowiedź • dodaj funkcj˛e aby wyświetlał dowolny plik • dodaj funkcj˛e aby listował dowolny katalog - wykorzystaj os.walk oraz os.path.join do łaczenia ˛ nazw katalogów • zmodyfikuj program aby przyjmował zapytania w formacie XML, pole command oraz arguments powinny być osobno • zmodyfikuj program aby przyjmował zapytania w formacie JSON, pole command oraz arguments powinny być osobno • stwórz dekorator localhost_only, który b˛edzie sprawdzał IP źródłowe połaczenia ˛ i jeżeli nie pochodzi z 127.0.0.1 odmówi wykonania polecenia • stwórz dekorator log_request, który weźmie parametry zapytania (IP, polecenie, argumenty) i zapisze je do pliku /tmp/botnet.log w formacie Request from IP:PORT to execute COMMAND ARGUMENTS Podpowiedź • subprocess.Popen • użyj os.path.join do łaczenia ˛ sciezki i nazwy pliku 5.9. Zadania 81 Python Workshop, Release 3f9e170, 2017-02-21 82 Chapter 5. Zaawansowany CHAPTER 6 Załaczniki ˛ Przydatne odnośniki Doumentacja • https://www.python.org - Strona do pobrania Pythona • https://pyformat.info - Formatowanie stringów w Python • http://devdocs.io Video • http://www.infoq.com/python/ • http://pyvideo.org/ • https://www.youtube.com/watch?v=-5wpm-gesOY Środowisko developerskie • https://www.jetbrains.com/pycharm/download/ Ponadto • https://python3wos.appspot.com - Python 3 lista kompatybilnych bibliotek • http://www.unixtimestamp.com • https://coloredlogs.readthedocs.io/en/latest/ Humor IT • http://geekandpoke.typepad.com • http://devopsreactions.tumblr.com 83 Python Workshop, Release 3f9e170, 2017-02-21 Inne Poniższe materiały i linki pochodza˛ z: programowanie-wstep-pod-/ * http://www.wykop.pl/wpis/9876900/python-naukaprogramowania- 2. Video (i inne): Screencasty / kursy video potrafia˛ sporo pomóc, nie korzystaj wyłacznie ˛ z nich, to po prostu kolejna pomoc naukowa. http://shop.oreilly.com/product/110000448.do - Dobra seria filmów dla bardzo poczatkuj ˛ acych, ˛ świetny materiał do ogladania ˛ na zmian˛e z czytaniem pierwszej ksia˛żki i eksperymentowaniem z pierwszymi programami. http://learnpythonthehardway.org/ - jest ksia˛żka złożona z praktycznie samych ćwiczeń oraz seria screencastów pokazujacych ˛ rozwiazania ˛ tych ćwiczeń. http://shop.oreilly.com/product/110000667.do - wst˛ep do algorytmów z użyciem pythona, należy uważać - prezenter pisze sporo kodu który jest uważany za nie-pythoniczny http://www.pluralsight.com/tag/python - wiele godnych uwagi serii screencastów ( mi˛edzy innymi ucza˛ cych podstawowego i zaawansowanego pythona, pisania aplikacji GUI w Qt), ale najważniejsza z nich: http://www.pluralsight.com/courses/python-developers-toolkit - to bardzo krótka seria uczacy ˛ najważniejszych i niemal niezb˛ednych każdemu programiście pythona narz˛edzi Filmy z ostatnich konferencji (dużo tego, każdy znajdzie coś dla siebie) https://www.youtube.com/playlist?list=PLBGl1tVyiWQSVwxne3yOH79uaSqgbnCqL - Kiwi Pycon 2014 https://www.youtube.com/playlist?list=PLE7tQUdRKcybbNiuhLcc3h6WzmZGVBMr3 Filmy z DjangoCon 2014 https://www.youtube.com/channel/UC45KSayx_kwQAnhpaPAuVkw/videos - Filmy z PyGotham 2014 http://pyvideo.org/category/56/pycon-australia-2014 http://pyvideo.org/category/55/pydataberlin-2014 http://pyvideo.org/category/54/europython-2014 http://pyvideo.org/category/52/pyohio-2014 http://pyvideo.org/category/51/scipy-2014 http://www.codecademy.com/en/tracks/python - to interaktywny kurs pythona w przegladarc˛ ˛ e, nie trzeba nic instalować, wystarczy wykonywać polecenia. Jest całkiem w porzadku, ˛ ale nie polecam go jako “jedynego” źródła wiedzy o Pythonie, oraz (ostatnio gdy sprawdzałem) nie wspierał Pythona 3. 3. Wyzwania i potyczki TO SUPER WAŻNE żebyś podczas czytania i ogladania ˛ programował i nie kopiował gotowego kodu z paczek źródłowych do ksia˛żek tylko r˛ecznie pisał, starajac ˛ si˛e zrozumieć co piszesz. Musisz eksperymentować, wprowadzać własne zmiany, pisać własne projekty i realizować własne pomysły. https://warosu.org/data/g/img/0441/94/1410874830625.png - zbiór 100 pomysłów na projekty treningowe aby nauczyć si˛e na nich programowania Strony z zadaniami i zagadkami algorytmicznymi, poćwicza˛ twoje myślenie i niejednokrotnie optymalizacj˛e kodu. Miłe oderwanie od innej nauki. Uwaga - nie przesadzać, bo wpadniesz w złe praktyki i spiral˛e przedwczesnej optymalizacji. http://pl.spoj.com/ http://codeeval.com/ https://www.reddit.com/r/dailyprogrammer https://www.hackerrank.com/ http://www.codechef.com/ Naucz si˛e j˛ezyka SQL i opanuj przynajmniej jeden system zarzadzania ˛ baza˛ danych: O SQL jest 4 tony całkiem niezłych ksia˛żek, kursów i tutoriali, łatwo znaleźć wi˛ec nic konkretnego nie podam. PostgreSQL - goraco ˛ polecam - http://www.postgresql.org/ MySQL (MariaDB) - https://www.mysql.com/ Oracle http://www.oracle.com/pl/products/database/overview/index.html Interesuj si˛e i badź ˛ na bieżaco: ˛ https://www.reddit.com/r/learnpython https://www.reddit.com/r/python https://www.reddit.com/r/learnprogramming https://www.reddit.com/r/programming Jeżeli prosisz kogoś o pomoc pami˛etaj żeby: - Wkleić kod na jakieś pastie - np. http://dpaste.com/ , http://hastebin.com/ - Sprawdzić czy kod faktycznie nie działa -u siebie i np na http://ideone.com/ - Wklejajac ˛ fragmenty kodu na wykop używać http://wykop-code.appspot.com/ w celu zachowania czytelności i wci˛eć - Opisać zrozumiale z czym masz problem i czego już probowałeś żeby temu zaradzić - Wkleić pełna˛ treść bł˛edu (jeżeli jest długo to na pastie) jeżeli takowy wystapił ˛ 84 Chapter 6. Załaczniki ˛ Python Workshop, Release 3f9e170, 2017-02-21 Python 2 vs. 3 six Python six Lista kompatybilności Python 2 i Python 3 Wall of Super Powers Unicode i kodowanie znaków Biblioteki standardowe w 2 i 3 Name builtins configparser copyreg cPickle cStringIO dbm_gnu _dummy_thread email_mime_multipart email_mime_nonmultipart email_mime_text email_mime_base filter filterfalse getcwd getcwdb http_cookiejar http_cookies html_entities html_parser http_client BaseHTTPServer CGIHTTPServer SimpleHTTPServer input intern map queue range reduce reload_module reprlib shlex_quote socketserver 6.2. Python 2 vs. 3 Python 2 name py2:__builtin__ py2:ConfigParser py2:copy_reg py2:cPickle py2:cStringIO.StringIO() py2:gdbm() py2:dummy_thread py2:email.MIMEMultipart py2:email.MIMENonMultipart py2:email.MIMEText py2:email.MIMEBase py2:itertools.ifilter() py2:itertools.ifilterfalse() py2:os.getcwdu() py2:os.getcwd() py2:cookielib py2:Cookie py2:htmlentitydefs py2:HTMLParser py2:httplib py2:BaseHTTPServer py2:CGIHTTPServer py2:SimpleHTTPServer py2:raw_input() py2:intern() py2:itertools.imap() py2:Queue py2:xrange() py2:reduce() py2:reload() py2:repr py2:pipes.quote py2:SocketServer Python 3 name py3:builtins py3:configparser py3:copyreg py3:pickle py3:io.StringIO py3:dbm.gnu py3:_dummy_thread py3:email.mime.multipart py3:email.mime.nonmultipart py3:email.mime.text py3:email.mime.base py3:filter() py3:itertools.filterfalse() py3:os.getcwd() py3:os.getcwdb() py3:http.cookiejar py3:http.cookies py3:html.entities py3:html.parser py3:http.client py3:http.server py3:http.server py3:http.server py3:input() py3:sys.intern() py3:map() py3:queue py3:range() py3:functools.reduce() py3:imp.reload(), py3:importlib.relo py3:reprlib py3:shlex.quote py3:socketserver Con 85 Python Workshop, Release 3f9e170, 2017-02-21 Name _thread tkinter tkinter_dialog tkinter_filedialog tkinter_scrolledtext tkinter_simpledialog tkinter_ttk tkinter_tix tkinter_constants tkinter_dnd tkinter_colorchooser tkinter_commondialog tkinter_tkfiledialog tkinter_font tkinter_messagebox tkinter_tksimpledialog urllib.parse urllib.error urllib.request urllib.response urllib.robotparser urllib_robotparser UserDict UserList UserString winreg xmlrpc_client xmlrpc_server xrange zip zip_longest Table 6.1 – continued from previous page Python 2 name Python 3 name py2:thread py3:_thread py2:Tkinter py3:tkinter py2:Dialog py3:tkinter.dialog py2:FileDialog py3:tkinter.FileDialog py2:ScrolledText py3:tkinter.scrolledtext py2:SimpleDialog py3:tkinter.simpledialog py2:ttk py3:tkinter.ttk py2:Tix py3:tkinter.tix py2:Tkconstants py3:tkinter.constants py2:Tkdnd py3:tkinter.dnd py2:tkColorChooser py3:tkinter.colorchooser py2:tkCommonDialog py3:tkinter.commondialog py2:tkFileDialog py3:tkinter.filedialog py2:tkFont py3:tkinter.font py2:tkMessageBox py3:tkinter.messagebox py2:tkSimpleDialog py3:tkinter.simpledialog See six.moves.urllib.parse py3:urllib.parse See six.moves.urllib.error py3:urllib.error See six.moves.urllib.request py3:urllib.request See six.moves.urllib.response py3:urllib.response py2:robotparser py3:urllib.robotparser py2:robotparser py3:urllib.robotparser py2:UserDict.UserDict py3:collections.UserDict py2:UserList.UserList py3:collections.UserList py2:UserString.UserString py3:collections.UserString py2:_winreg py3:winreg py2:xmlrpclib py3:xmlrpc.client py2:SimpleXMLRPCServer py3:xmlrpc.server py2:xrange() py3:range() py2:itertools.izip() py3:zip() py2:itertools.izip_longest() py3:itertools.zip_longest() Httplib w 2 i 3 Python 3.5 i deklaracja typów def suma(a: int, b: int) -> int: return a + b Wybór IDE Czym jest IDE? Do edycji skryptów Pythona wystarczy sam Notatnik. Kod źródłowy jest na tyle czytelny i prosty, że bardzo łatwo b˛edziemy w stanie poradzić sobie z prostymi skryptami bez jakiejkolwiek pomocy od zaawansowanego edytora. Jednakże w miar˛e rośni˛ecia złożoności projektu oraz ilości plików przyda nam si˛e coś co ułatwi nam prac˛e. Wybór edytora to temat wielce kontrowersyjny. Od kilku dziesi˛ecioleci w środowisku programistów jest prowadzona wojna mi˛edzy minimalistycznym VIMem oraz posiadajacym ˛ ogromne możliwości EMACSem. Jeden i drugi edytor 86 Chapter 6. Załaczniki ˛ Python Workshop, Release 3f9e170, 2017-02-21 wspaniale posłuży nam do pisania skryptów w Pythonie i po odpowiedniej konfiguracji lub instalacji pluginów podpowie składni˛e. I choć sam jestem fanem jednego z powyższych rozwiazań ˛ (ale nie powiem którego :) to do wi˛ekszych projektów korzystam z czegoś zupełnie z innej beczki. Po przetestowaniu kilkunastu środowisk IDE zaprzyjaźniłem si˛e z edytorem PyCharm. PyCharm ma dwie wersj˛e płatna˛ oraz darmowa.˛ Ta druga w zupełności nam wystarczy. Ciekawa˛ alternatywa˛ może być PyDev - plugin do środowiska Eclipse. W poniższych materiałach b˛ed˛e posługiwał si˛e kodem źródłowym, który wykonywany jest przez interpreter i nie ma znaczenia z jakiego IDE skorzystasz. Poniższe materiały i linki pochodza˛ z: programowanie-wstep-pod-/ * http://www.wykop.pl/wpis/9876900/python-naukaprogramowania- Korzystaj z dobrego IDE (lub edytora): W kategorii IDE jest PyCharm i później długo długo nic. Należy si˛e z tym pogodzić i nie zaprzeczać rzeczywistości, ponieważ ani Wingware ani Komodo IDE (konkurencja) nie graja˛ w tej samej lidze. Darmowa wersja “Community Edition” powinna jak najbardziej wystarczyć do nauki Pythona. Jeżeli IDE uważasz za coś potwornego i zb˛ednego - to si˛e mylisz, ale nie mam zamiaru ci˛e w tym miejscu przekonywać. Dla takich ludzi jak ty też jest nadzieja. Zarówno dobrze skonfigurowany vim jak i Sublime Text 3 moga˛ posłużyć za dobry edytor do nauki Pythona. Korzystaj z dobrego interpretera: Pobierz najnowsza˛ wersj˛e z serii 3 (w tej chwili to 3.4.2) bezpośrednio z: https://www.python.org/downloads/ Znaj narz˛edzia potrzebne do pracy w dobrym środowisku pythona: (uczy tego wyżej już wymienione http://www.pluralsight.com/courses/python-developers-toolkit ) Pomocny może okazać si˛e też taki podr˛ecznik: http://docs.python-guide.org/en/latest/ Pip - http://pip.readthedocs.org/en/latest/index.html Virtualenv - http://virtualenv.readthedocs.org/en/latest/ Debugger - http://pymotw.com/2/pdb/ Nauczyć si˛e ładnego formatowania kodu i odpowiedzi na najcz˛eściej zadawane pytania: To niezmiernie ważne, szacuje si˛e że ponad 80% kodu napisanego w Pythonie stosuje si˛e do poniższych zasad. http://legacy.python.org/dev/peps/pep0008/ https://code.google.com/p/google-styleguide/ Poznaj filozofi˛e Pythona: http://legacy.python.org/dev/peps/pep-0020/ https://gist.github.com/evandrix/2030615 Naucz si˛e GITa (system kontroli wersji): http://git-scm.com/book https://try.github.io/ https://www.atlassian.com/git/ http://www.git-tower.com/learn/ebook/command-line/introduction Publikuj swój kod i czytaj kod innych: https://github.com/ https://bitbucket.org/ Ekosystem Narzediowy ˛ Code Quality PEP8 About Python style guide checker. pep8 is a tool to check your Python code against some of the style conventions in PEP 8. • Plugin architecture: Adding new checks is easy. • Parseable output: Jump to error location in your editor. • Small: Just one Python file, requires only stdlib. You can use just the • pep8.py file for this purpose. • Comes with a comprehensive test suite. Installation 6.4. Ekosystem Narzediowy ˛ 87 Python Workshop, Release 3f9e170, 2017-02-21 pip install pep8 pip install --upgrade pep8 pip uninstall pep8 Usage pep8 pep8 pep8 pep8 FILENAME.py DIRECTORY/ --statistics -qq DIRECTORY/ --show-source --show-pep8 FILENAME.py Config setup.cfg [pep8] max-line-length = 939 ignore = E402,W391 SonarQube About SonarQube software (previously called Sonar) is an open source quality management platform, dedicated to continuously analyze and measure technical quality, from project portfolio to method. More information • https://sonarqube.com • http://docs.sonarqube.org/display/SONAR/Documentation • https://sonarqube.com/dashboard/index?did=143 • https://sonarqube.com/governance?id=662857 Pylint About Pylint is a Python source code analyzer which looks for programming errors, helps enforcing a coding standard and sniffs for some code smells (as defined in Martin Fowler’s Refactoring book). Pylint has many rules enabled by default, way too much to silence them all on a minimally sized program. It’s highly configurable and handle pragmas to control it from within your code. Additionally, it is possible to write plugins to add your own checks. Install pip install pylint pip install --upgrade pylint pip uninstall pylint Usage pylint DIRECTORY/ pylint FILENAME.py More information • https://pypi.python.org/pypi/pylint/ 88 Chapter 6. Załaczniki ˛ Python Workshop, Release 3f9e170, 2017-02-21 Pyflakes About A simple program which checks Python source files for errors. Pyflakes analyzes programs and detects various errors. It works by parsing the source file, not importing it, so it is safe to use on modules with side effects. It’s also much faster. Install pip install pyflakes pip install --upgrade pyflakes pip uninstall pyflakes Usage pyflakes DIRECTORY/ python -m pyflakes DIRECTORY/ More information • https://pypi.python.org/pypi/pyflakes Coverage About Coverage.py measures code coverage, typically during test execution. It uses the code analysis tools and tracing hooks provided in the Python standard library to determine which lines are executable, and which have been executed. Install pip install coverage pip install --upgrade coverage pip uninstall coverage Usage coverage run FILENAME.py coverage report -m More information • https://pypi.python.org/pypi/coverage • https://coverage.readthedocs.io/ unittest Usage python -m unittest FILENAME.py Automation and Releases Fabric Install 6.4. Ekosystem Narzediowy ˛ 89 Python Workshop, Release 3f9e170, 2017-02-21 pip install fabric pip install --upgrade fabric pip uninstall fabric Testy Mutacyjne • https://pypi.python.org/pypi/MutPy Transifex • https://www.transifex.com Ksiażki ˛ Design patterns • Design Patterns: Elements of Reusable Object-Oriented Software Refactoring • Working effectively with legacy code Quality • Clean Code Python Poniższe materiały i linki pochodza˛ z: programowanie-wstep-pod-/ * http://www.wykop.pl/wpis/9876900/python-naukaprogramowania- http://www.amazon.com/Learning-Python-Edition-Mark-Lutz/dp/1449355730/ to podstawowa pozycja, dobra, do nauki Pythona. Jednocześnie uczy/pokazuje Pythona 2 jak i 3. Jeżeli ktoś chce mieć, w miar˛e, wszystko w jednym miejscu, to warto si˛e w ta˛ ksia˛żk˛e zaopatrzyć. Ważne żeby to było wydanie 5, a nie wcześniejsze. http://www.amazon.com/Python-Programming-Introduction-Computer-Science/dp/1590282418/ Ci którzy znaja˛ już jakiś j˛ezyk bardzo dobrze lub studiuja˛ informatyk˛e moga˛ chcieć zamiast ksia˛żki Lutza wybrać ta˛ pozycj˛e. Jest krótsza, zwi˛eźlejsza i tłumaczy znacznie mniej, szczególnie rzeczy podstawowych. Wydanie drugie zostało zaktualizowane na potrzeby Pythona 3. http://inventwithpython.com/ Jeżeli jesteś #cebula i nie chcesz wydać ani złotówki na pierwsza˛ ksia˛żk˛e, jest dla ciebie nadzieja. Al Sweigart napisał ksia˛żki uczace ˛ programować w Pythonie przy okazji tworzenia prostych gier lub poznawania podstaw kryptografii. Oprócz sprzedawania ich na Amazonie, udost˛epnia je też za darmo na swojej stronie. Pozycje obowiazkowe ˛ (numer 2, 3 i 4): http://www.amazon.com/Python-Cookbook-David-Beazley/dp/1449340377/ 90 Chapter 6. Załaczniki ˛ Python Workshop, Release 3f9e170, 2017-02-21 To jest ksia˛żka która powinna si˛e znaleźć u każdego na półce niezależnie od obranej drogi nauki. Pozycja absolutnie obowiazkowa. ˛ Zawiera ton˛e (kilkaset?) gotowców, podzielonych na kategori˛e z wyjaśnieniem jaki problem rozwiazuj ˛ a˛ oraz dlaczego tak a nie inaczej. Wydanie trzecie, wspiera oczywiście Pythona 3. https://www.jeffknupp.com/writing-idiomatic-python-ebook/ Ebook z kategorii obowiazkowych. ˛ Uczy jak pisać kod uważany za Pythonowy i unikać szkodliwych kalek np. z C++. Jest wersja dla Pythona 3. http://www.amazon.com/Python-Practice-Concurrency-Libraries-Developers/dp/0321905636/ wzorce projektowe, programowanie współbieżne. Warta każdej złotówki. Dobre praktyki, Tyle jeżeli chodzi o pozycje obowiazkowe, ˛ jest jednak jeszcze par˛e ciekawych pozycji, które mog˛e polecić: http://learnpythonthehardway.org/book/ - darmowa wersja ksia˛żki złożonej z praktycznie samych ćwiczeń http://anandology.com/python-practice-book/index.html - jeszcze wi˛ecej ćwiczeń http://www.amazon.com/Python3-Object-Oriented-Programming/dp/1849511268/ - ksia˛żka uczaca ˛ (i skupiajaca ˛ si˛e tylko na tym) koncepcji programowania obiektowego na konkretnych przykładach Pythona 3 http://shop.oreilly.com/product/0636920032519.do - pozycja w trakcie tworzenia, zapowiada si˛e na dobra˛ ksia˛żk˛e o zaawansowanym pythonie. Znajomość j˛ezyka to jednak nie wszystko i jeżeli chcesz być ogólnie kompetentnym programista˛ polecam poniższe ksia˛żki: Algorytmy: http://www.amazon.com/Introduction-Algorithms-Edition-Thomas-Cormen/dp/0262033844/ http://www.amazon.com/Algorithms-4th-Edition-Robert-Sedgewick/dp/032157351X/ Wzorce obiektowe: http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612/ Bazy danych: http://www.amazon.com/Database-Design-Mere-Mortals-Hands-/dp/0321884493/ http://www.amazon.com/SQL-Antipatterns-Programming-Pragmatic-Programmers/dp/1934356557/ Pozycje nieobowiazkowe, ˛ ale najdogł˛ebniejsze - http://www.amazon.com/C.-J.-Date/e/B000AQ6OJA/ Dobre praktyki i inne: http://www.amazon.co.uk/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882/ http://www.amazon.com/Pragmatic-Programmer-Journeyman-Master/dp/020161622X/ http://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670/ http://www.amazon.com/The-Mythical-Man-Month-Engineering-Anniversary/dp/0201835959/ Python WAT?! >>> 999 + 1 is 1000 False >>> 1 + 1 is 2 True >>> 2.2 * 3.0 == 3.3 * 2.0 False >>> a = ('hello', 'word') >>> a = ('hello') >>> for x in a: ... print(x) h e l l o >>> a = ('hello', 'word') >>> a = ('hello',) 6.6. Python WAT?! 91 Python Workshop, Release 3f9e170, 2017-02-21 >>> for x in a: ... print(x) hello >>> a = 'hello', 'word' >>> a = 'hello' >>> for x in a: ... print(x) h e l l o >>> a = 'hello', 'word' >>> a = 'hello', >>> for x in a: ... print(x) hello 92 Chapter 6. Załaczniki ˛ CHAPTER 7 Receptury LDAP Expiring Passwords #!/usr/bin/env python3 import datetime import time from pprint import pprint from ldap3 import Server, Connection, SEARCH_SCOPE_WHOLE_SUBTREE USER = "myusername" PASS = "mypassword" BASEDN = "OU=Users,DC=local" SERVER = Server("127.0.0.1", port=389) ATTRIBUTES = ['mail', 'pwdLastSet'] def construct_filter(wintimestamp): return """(& (objectCategory=Person) (objectCategory=User) (userAccountControl=512) (pwdLastSet<={wintimestamp}) (mail=*) )""".format(wintimestamp=wintimestamp) def search(filter): with Connection(SERVER, user=USER, password=PASS) as c: c.search(BASEDN, filter, SEARCH_SCOPE_WHOLE_SUBTREE, attributes=ATTRIBUTES) return [record['attributes'] for record in c.response] def datetime_to_mstimestamp(date): """ Active Direcotry has different approach to create timestamp than Unix. Here's a function to convert the Unix timestamp to the AD one. >>> datetime_to_mstimestamp(datetime.datetime(2000, 1, 1, 0, 0)) 125911548000000000 """ 93 Python Workshop, Release 3f9e170, 2017-02-21 timestamp = int(time.mktime(date.timetuple())) magic_number = 116444736000000000 return timestamp * 10000000 + magic_number def mstimestamp_to_datetime(mstimestamp): """ Active Direcotry has different approach to create timestamp than Unix. Here's a function to convert AD timestamp to the Unix one. >>> mstimestamp_to_datetime(130567328471235643) datetime.datetime(2014, 10, 2, 16, 14, 7, 123563) """ magic_number = 11644473600 return datetime.datetime.fromtimestamp( mstimestamp / 10000000 - magic_number) def month_ago(date): """ >>> month_ago(datetime.datetime(2000, 1, 31, 0, 0)) datetime.datetime(2000, 1, 1, 0, 0) """ return date - datetime.timedelta(days=30) def print_users_with_expiring_password(): now = datetime.datetime.now() expiration_date = month_ago(now) wintimestamp = datetime_to_mstimestamp(expiration_date) older_than_month_ago = construct_filter(wintimestamp) for user in search(older_than_month_ago): user['pwdLastSet'] = mstimestamp_to_datetime( int(user['pwdLastSet'][0])) pprint(user) if __name__ == "__main__": print_users_with_expiring_password() 94 Chapter 7. Receptury