Wstęp

Przedmowa

Geneza języka

  • Open Source,

  • Nazwa języka pochodzi od serialu BBC Latający Cyrk Monty Pythona. Twórca jest fanem serialu,

  • Python (jego interpreter) zaczął powstawać od 1989,

  • Guido van Rossum - były dobrotliwy, dożywotni dyktator. Jest jak Linus Torvalds dla kernela Linuxa,

  • Potrzeba było łatwe tworzenie narzędzi systemowych do systemu operacyjnego Amoeba,

  • Coś co byłoby pomiędzy językiem C a Shell,

  • Python 2.0 – październik 2000,

  • Python 3.0 - grudzień 2008

Zastosowanie

  • DevOps

    • Boto3,

    • Redhat - narzędzia,

      • Instalator Anaconda,

      • system-config-network-tui,

      • system-config-services,

      • inne system-config-,

      • instalatory paczek (yum - python2, dnf - python3),

      • OpenStack,

      • Ansible ( zarządzanie konfiguracją / wdrożeniem )

  • Data Science / Machine Learning

    • sklearn,

    • Tensorflow,

    • pySpark

  • Web Development

    • Django,

    • Flask

Kto używa

  • Google – jako główny język w firmie, obok jest Java oraz C++. Do przetwarzania ogromnej ilości danych od użytkowników,

  • Netflix – do skalowania infrastruktury, alerty w przypadku zmiany ustawień zabezpieczeń,

  • Instagram (framework Django), Facebook (Framework Tornado),

  • Spotify (Duży wolumen danych do przeprocesowania – Luigi),

  • Nasa

Instalacja

Windows

  • Instalator exe dostępny na stronie.

Mac

  • Najlepiej poprzez instalację z brew,

  • Ewentualnie przy użyciu instalatora ze strony

Linux

  • Na debianie lub ubuntu sudo apt-get update && sudo apt-get install python python3-pip python3-venv

  • Na fedorze sudo dnf install python albo konkretna wersja sudo dnf install python37

Hint

Aby sprawdzić używaną wersję pythona wykonujemy polecenie: python --version lub python -V

Kod źródłowy

Środowisko uruchomieniowe

Pythona można uruchomić na kilka sposobów w zależności od zapotrzebowania.

Środowisko wirtualne (venv)

  • Odseparowuje środowiska od siebie,

  • Rozwiązuje problem konfliktów wersji,

  • Pozwala utrzymywać różne wersje bibliotek/pythona w naszych projektach

Note

Aby stowrzyć środowisko wirtualne wykonujemy jedno z dwóch poleceń - python -m venv <KATALOG> zamiast KATALOG najczęściej występuje venv lub env - virtualenv <KATALOG> np. virtualenv venv

Note

Uby użyć środowiska musimy wykonać dodatkowe polecenia: source venv/bin/activate

Hint

W przypadku Windows użytkownik aktywuje środowisko bez użycia source

Środowisko globalne

  • Wszystkie paczki są globalne - nie ma separacji,

  • Często pojawiają się problemy z zależnościami

Środowisko w kontenerze

  • Python dostępny jedynie w kontenerze,

  • Dobre rozwiązanie w przypadku testowania oprogramowania,

  • Integralna część obecnych środowisk CI/CD

Edytory

Sublime

Vim

Atom

Inne

Ide

pyCharm

Płatne środowisko od JetBrains * Dużo pluginów, * Wsparcie dla Frameworków, * Integracja z Docker, bazami danych, konsolą, usługami chmurowymi

pycharm screenshot

Visual Studio Code

  • Narzędzie darmowe,

  • Trzeba dogrywać pluginy aby rozszerzyć możliwości

Eclipse

  • Narzędzie darmowe

Spyder

  • Narzędzie darmowe

  • Używane w celach naukowych lub analizie danych. Mało popularny, wyparty raczej przez Jupyter Notebook

IDLE

  • Narzędzie darmowe,

  • Niezalecane,

  • Trudny proces developmentu

Python

Język strukturalny

  • Możliwe jest pisanie prostych skryptów

Język obiektowy

  • Wszystko jest obiektem

Język funkcyjny

>>> liczby = [1, 2, 3, 4, 5]
>>> potegi_dwojki = [2**n for n in liczby]
>>> potegi_dwojki
[2, 4, 8, 16, 32]

Dynamicznie typowany

  • Typy określane są w trakcie wykonania programu,

  • Z jednej strony swoboda, z drugiej wolniejsze oprogramowanie,

  • Brak kompilacji - błędy związane ze złym typem pojawiają się dopiero po uruchomieniu wadliwej linni kodu

miejsce = 43 # int
miejsce = "przy oknie" # str
print(miejsce)

W wyniku zostanie nadpisana zmienna (również typ się zmieni)

przy oknie

Garbage collector

  • Zarządza oczyszczaniem pamięci,

  • Oparty na algorytmie zliczającym ilość referencji na dany obiekt

Przekazywanie wartości przez referencje

Powłoki Python

python

  • domyślnie zainstalowany shell

ipython

  • można łatwo doinstalować,

  • posiada dodatkowe funkcje,

  • koloruje składnie

jupyter-notebook

  • oparty na ipython,

  • używany najczęściej w zespołach data science,

  • oferuje dodatkowe funckje jak np. drukowanie projektu z kodem

Konwencje nazewnicze

Wcięcia

  • Definiują blok podprogramu np. w definicji funkcji, klasy czy bloku if/else,

  • Nie można mieszać tabulatora z czteroma spacjami,

  • 4 spacje - jako zalecany sposób,

  • tabulator jest dozwolony (lecz jeśli zaczynamy lepiej użyć spacji),

  • można ustawić środowisko aby tabulator był zamieniany na 4 spacje

Systemy notacji

lower_case_with_underscores

Używane do:

  • Nazw funkcji,

  • Nazw parametrów,

  • Nazw pakietów,

  • Nazw modułów,

def pole_kwadratu(a, b):
    return a * b

print(pole_kwadratu(5, 4))

Poniżej wypisane pole kwadratu o bokach 4 i 5

20

CAPS_WITH_UNDER

  • zmienne globalne,

  • stałe zdefiniowane w klasie

>>> PI = 3.14

PascalCase

Note

PascalCase lub UpperCamelCase to styl w którym:

  • Wyrazy pisane są łącznie,

  • Każdy wyraz pisany jest wielką literą,

PascalCase jako nazwa typu danych

>>> from pandas import DataFrame

PascalCase użyty do definiowania klasy

class SportsCar:
  def __init__(self, name):
      self.name = name

# Utworzenie obiektu porsch klasy SportsCar
porsch = SportsCar("porsche")
print(porsch.name)

Poniżej wypisany atrybut: nazwa

porsche

Hint

Wyjątki powinny być klasą, stąd też pisane są PascalCase

Źródła

Sprawdź PEP 8

Warning

Przestrzeganie 79 znaków w linni obecnie może wydawać się nieaktualne

Pep8

Użycie lintera

pylint code_file.py
pylint result

Annotations

def dodaj_liczby(a: int, b: int) -> int:
    return a + b

print(dodaj_liczby(2, 3))
5

Źródła

Sprawdź PEP 8

Warning

Przestrzeganie 79 znaków w linni obecnie może wydawać się nieaktualne

Podstawy

Podstawy

Ciągi znaków

Wypisywanie ciągów znaków

>>> print('Hello World!')
Hello World!

albo w innej formie cudzysłowów >>> print(“Hello World!”) Hello World!

Definiowanie

tekst = "Hello World!"
print(tekst)
Hello World!

Sprawdzenie typu

>>> type(tekst)
<class 'str'>

Sprawdzenie długości napisu

>>> len(tekst)
12

Wyświetlanie specjalnych znaków

  • Znak nowej linni

>>> print("Hello\nWorld!")
Hello
World!
  • Znak tabulatora

>>> print("Hello\tWorld!") 

Konkantenacja znaków

>>> print('Hello ' +  'uczestniku')
Hello uczestniku

Konkantenacja znaków - format

>>> print('Hello {}, have a great day'.format('Tomasz'))
Hello Tomasz, have a great day

Różne reprezentacje - format

>>> '{:s}'.format('Ciąg znaków') # w przypadku podania liczby zamiast stringa - wyjątek
'Ciąg znaków'
class Data:
    """Simple Data class"""
    def __str__(self):
        return 'str'

    def __repr__(self):
        return 'repr'


print("{0!s} {0!r}".format(Data(), Data()))
print("{obiekt!s} {obiekt!r}".format(obiekt=Data()))
str repr
str repr
>>> '{:>10}'.format('test')
'      test'
>>> '{:10}'.format('test')
'test      '
>>> '{:^10}'.format('test')
'   test   '

Funkcje dostępne na stringach

>>> 'Hello'.endswith('o')
True
>>> 'Hello'[-1] == 'o'
True

Podciągi w ciągach znaków

>>> 'Hello'[-1]
'o'
>>> 'Hello'[0:6:2]
'Hlo'
imiona = 'Marta, Kasia, Monika, Tomek, Przemek, Janek, Marta, Malgosia'

print(imiona.count('Ma'))

W wyniku dostajemy ilość wystąpień ciągu

3
>>> imiona.find('Kasia')
7

Dzielenie ciagów po danym seperatorze

>>> imiona.split(',')
['Marta', ' Kasia', ' Monika', ' Tomek', ' Przemek', ' Janek', ' Marta', ' Malgosia']

Otrzymaliśmy listę ciągów

Operacje na stringach

>>> imiona = imiona.replace("Janek", "Adam")
>>> print(imiona)
Marta, Kasia, Monika, Tomek, Przemek, Adam, Marta, Malgosia

Sprawdzenie czy ciąg jest liczbą

>>> imiona.isdigit()
False
>>> temperatura = "34"
>>> print(temperatura.isdigit())
True

Pisanie ciągu z wielkich liter

>>> print(imiona.upper())
MARTA, KASIA, MONIKA, TOMEK, PRZEMEK, ADAM, MARTA, MALGOSIA

Pisanie ciągu z małych liter

>>> print(imiona.lower())
marta, kasia, monika, tomek, przemek, adam, marta, malgosia

Zadania

  • Stwórz program wypisujący twoje imienie i nazwisko,

  • Stwórz kod wypisujący: “Test znaków: ‘, /, ” “

  • Stwórz dwóch uczestników szkolenia ( wybierz dowolne imiona i przypisz do osobnych zmiennych)

    • pierwszy_uczestnik,

    • drugi uczestnik

  • Zamień uczestników miejscami

    • Wypisz uczestników,

    • Czy jest możliwy inny sposób na zamianę miejsc ?

  • Niech użytkownik podaje swoje imie przy każdym uruchomieniu kodu (Użyj google)

Liczby całkowite

Definiowanie

>>> wynagrodzenie_netto = 8000
>>> print(wynagrodzenie_netto)
8000

Sprawdzenie typu

>>> type(wynagrodzenie_netto)
<class 'int'>

Przyrównanie typów: string oraz integer

>>> wynagrodzenie_str = '8000'
>>> wynagrodzenie_str == wynagrodzenie_netto
False

Konwersja typów

>>> wynagrodzenie_converted = int(wynagrodzenie_str)
>>> wynagrodzenie_converted == wynagrodzenie_netto
True

Operacje na liczbach

Po podwyżce dostajemy o 5% więcej pieniędzy

>>> wynagrodzenie_netto = wynagrodzenie_netto*1.05
>>> print(wynagrodzenie_netto)
8400.0
>>> type(wynagrodzenie_netto) == float
True
>>> type(wynagrodzenie_netto)
<class 'float'>

Dodawanie - dostaliśmy miesięczny bonus 200 zł

>>> wynagrodzenie_netto += 200
>>> wynagrodzenie_netto = int(wynagrodzenie_netto)
>>> print(wynagrodzenie_netto)
8600

Dzielenie całkowito liczbowe - Chcemy policzyć jaki jest dochód netto na osobę w 3 osobowej rodzienie, - Przyjmniej dokładnośc do drugiego miejsca po przecinku (zaokrąglenie)

>>> print(round(wynagrodzenie_netto / 3, 2))
2866.67
>>> wynagrodzenie_netto // 3
2866

Jak widzimy straciliśmy precyzję. Wartości po przecinku zostały zignorowane

Dzielenie modulo - Sprawdzenie czy nasza kwota jest liczbą parzystą

>>> print(wynagrodzenie_netto % 2)
0

Nie ma reszty z dzielenia - więc liczba jest parzysta

Liczby zmienno przecinkowe

Definiowanie

>>> wynagrodzenie_netto = 8000.63
>>> print(wynagrodzenie_netto)
8000.63

Sprawdzenie typu

>>> type(wynagrodzenie_netto)
<class 'float'>

Konwersja typów

>>> wynagrodzenie_converted = int(wynagrodzenie_netto)
>>> wynagrodzenie_converted == wynagrodzenie_netto
False

Ciekawostki

>>> print(0.1 + 0.2)
0.30000000000000004

Hint

Podpowiedz na stronie.

Dodatkowo wpis na wikipedi.


import decimal

ctx = decimal.getcontext() print(ctx)

a = decimal.Decimal(0.2) b = decimal.Decimal(0.1)

ctx.prec = 6 print(a + b)

Zadania

  • Oblicz sumę liczb 123, 321, 675 oraz wyświetl ją na ekranie,

  • Sprawdz czy suma ta jest wielokrotnością liczby 5,

  • Oblicz należny podatek (linniowy 19%) od kwoty podanej przez użytkownika (input). Załóż że kwota wolna od podatków to 5000

  • oblicz pole koła (o podanym promieniu przez użytkownika), zaimportuj dodatkowy moduł google

Listy

Definiowanie

>>> lista_plac = [4000, 5000, 3000, 8000]
>>> print(lista_plac)
[4000, 5000, 3000, 8000]

Sprawdzenie typu

>>> type(lista_plac)
<class 'list'>

Operacje na listach

  • Sprawdzenie długości listy

>>> len(lista_plac)
4
  • Sprawdzanie wystąpienia elementu

>>> 3000 in lista_plac
True
  • Dodanie elementu do listy

lista_plac.append(12000)
print(lista_plac)
[4000, 5000, 3000, 8000, 12000]
  • Wstawienei elementu na konkretną pozycję listy

lista_plac.insert(1, 4500)
print(lista_plac)
[4000, 4500, 5000, 3000, 8000, 12000]
  • Posortowanie listy

lista_plac = sorted(lista_plac)
print(lista_plac)
[3000, 4000, 4500, 5000, 8000, 12000]
print(sorted(lista_plac, reverse=True))
[12000, 8000, 5000, 4500, 4000, 3000]
lista_plac.extend([2800, 15000])
lista_plac.sort()
print(lista_plac)
[2800, 3000, 4000, 4500, 5000, 8000, 12000, 15000]

Wyciąganie ostatniego elementu z listy

>>> wydobyty = lista_plac.pop()
>>> print(wydobyty)
15000

Ponownie “dorzucimy” element do listy

>>> lista_plac.append(wydobyty)
>>> print(lista_plac)
[2800, 3000, 4000, 4500, 5000, 8000, 12000, 15000]

Dorzucimy też element który jest niepoprawny (ujemne wynagrodzenie)

>>> lista_plac.append(-300)
>>> print(lista_plac)
[2800, 3000, 4000, 4500, 5000, 8000, 12000, 15000, -300]

Taki element jest nam niepotrzebny - usuniemy go:

>>> del lista_plac[-1]
>>> print(lista_plac)
[2800, 3000, 4000, 4500, 5000, 8000, 12000, 15000]

Konwersja typów

  • to tupli

tupla_plac = tuple(lista_plac)
print(tupla_plac)
(2800, 3000, 4000, 4500, 5000, 8000, 12000, 15000)
  • do set-a

>>> set_plac = set(lista_plac)
>>> print(set_plac)  

Zadania

Pierwsze

  • Stwórz listę składających się z elementów:

  • A = „audi”

  • B = „bmw”

  • C = „mercedes”

  • D = „mazda”

  • Zamień Audi z Mazdą miejscami

  • Usuń ostatni samochód

  • Wypisz ostatni element z listy

Drugie

  • Utwórz listę temperatu [-5, -4, 0, -3, -2, 9, 10],

  • Posortuj od największej,

  • Przeiteruj listę od tyłu,

  • Czy jest jakaś różnica ?

Słowniki

Typ danych klucz - wartość

Definiowanie

>>> pracownicy = {1: 'Adam', 3: 'Tomasz', 4: 'Kasia'}
>>> print(pracownicy) 

Sprawdzenie typu

>>> type(pracownicy)
<class 'dict'>

Operacje na slownikach

  • Sprawdzenie długości słownika

>>> len(pracownicy)
3
  • Sprawdzanie wystąpienia elementu

>>> 3000 in pracownicy
False
>>> 1 in pracownicy
True

Pracownik o id 1 znajduje sie w slowniku

  • Dodanie elementu do listy

>>> pracownicy[15] = "Marek"
>>> print(pracownicy) 
>>> print(len(pracownicy))
4

Zadania

Pierwsze

  • Utwórz słownik ze stolicami:

    • Francji, Niemiec, Polski, Czech

    • Sprawdz stolicę Uk - w przypadku braku wyświetl “stolica nieznana” google

    • Dodaj stolicę Uk - Jeśli brakuje

    • Usuń stolicę Czech ze słownika

Sety

Typ danych - tak jak zbióry w matematyce

Definiowanie

>>> A = {1, 2, 3, 4, 5}
>>> B = {4, 5, 6, 7, 8}

Sprawdzenie typu

>>> type(A)
<class 'set'>

Operacje na zbiorach

  • Sprawdzenie długości zbioru

>>> len(A)
5
  • Sprawdzanie wystąpienia elementu

>>> 17 in A
False
>>> 3 in A
True
  • Dodanie elementu do listy

>>> A.add(17)
>>> 17 in A
True
  • Unia

>>> C = A | B
>>> print(C.issuperset(A))
True
>>> print(C.issuperset(A))
True
  • Część wspólna

>>> D = A & B
>>> print(D) 
  • Różnica

>>> E = A - B 
>>> F = B - A 
  • Różnica symetryczna

>>> print(A.symmetric_difference(B)) 

Zbiory imutowalne

>>> A = frozenset([1, 2, 3, 4])

Implementacja

Kod w C do podejrzenia

Zadania

Pierwsze

  • mając biory:

    • A = {‘wp.pl’, ‘onet.pl’, ‘google.com’, ‘ing.pl’, ‘facebook.com’}

    • B = {‘wp.pl’, ‘youtube.pl’, ‘wikipedia.org’, ‘ovh.com’, ‘facebook.com’}

  • Znajdz:

    • Te domeny które w obu zbirach są wspolne

    • Domeny występującę wyłącznie albo w jednym albo w drugim zbiorze

Drugie

  • mając listę [1, 2, 4, 5, 7, 7, 7] wyświetl jedynie jej unikatowe wartości

Sterowanie wykonaniem kodu

Instrukcje warunkowe

  • if-y

if True:
    print('Wartość prawdziwa')

Powyższy kod zwraca tekst:

Wartość prawdziwa
if False:
    print('Wartość fałszywa')

Konwersje typów do Boolean

if []:
    print('Lista z zawartoscia')
else:
    print('Lista pusta')

Powyższy kod zwraca tekst:

Lista pusta

Sprawdzanie wartości logicznych

>>> bool(-1)
True
>>> bool(0)
False
>>> bool(124)
True
>>> bool({})
False

Sprawdzanie zakresów

temperatura = 18

if 16 <= temperatura < 24:
    print('Temperatura dobra na rower')
else:
    print('Temperatura nieodpowiednia na jazdę rowerem')
Temperatura dobra na rower
temperatura = -3

if 16 <= temperatura < 24:
    print('Temperatura dobra na rower')
elif 3 <= temperatura < 16:
    print('Temperatura dobra na spacer')
elif -5 <= temperatura < 3:
    print('Temperatura dobra na narty')
else:
    print('Niewiadomo co robić :(')
Temperatura dobra na narty

Zadania

Pierwsze

  • Nie użytkownik poda swój wiek, sprawdź czy jest pełnoletni,

  • Niech użytkownik poda liczbę, sprawdź czy liczba ta jest int czy float

Drugie

  • Stwórz prosty kalkulator BMI który będzie przyjmował wartości z input w wyniku będzie zwracał status czy masz nadwagę, niedowagę czy w normie

Trzecie

  • Użyj biblioteki os funkcji system aby sprawdzić czy host jest aktywny

    • W zależności od stanu wyświetl stosowny komunikat,

Pętle

for

for i in range(5):
    print(i)
0
1
2
3
4
for i in range(2, 6):
    print(i)
2
3
4
5
for i in range(2, 7, 2):
    print(i)
2
4
6

while

# i to nasz iterator
i = 0
while i < 10:
    print(i)
    i += 1
0
1
2
3
4
5
6
7
8
9
# i to nasz iterator
i = 6
while i < 10:
    if i == 7:
        print('Szczęśliwa 7ka')
        i += 1
        continue

    print(i)

    i += 1
6
Szczęśliwa 7ka
8
9
# i to nasz iterator
i = 6
while i < 10:
    if i == 7:
        print('Szczęśliwa 7ka ?')
        break

    print(i)

    i += 1
6
Szczęśliwa 7ka ?

iterowanie po iterables

for samochod in ['BMW', 'Audi', 'Mercedes']:
    print(samochod)
BMW
Audi
Mercedes

Zadania

Pierwsze

  • Utwórz słownik hostów których zapiszesz datę wykonania “skanowania” oraz status czy się powiodło

    • Możesz zdefiniować listę hostów np. wp.pl, google.com, ing.pl, nieistniejacyhost.domena

    • Możesz użyć biblioteki datetime google

    • Spróbuj zczytać datę dostępną w systemie (os.popen)

Drugie

  • Utwórz listę parzystych liczb z zakresu 0, 100,

  • Wyświetl listę

List/Dict/Set comprehensions

Używa się w celu zwiększenia czytelności kodu.

Hint

Z początku warto napisać wersję linniową, dopiero później przejść na “comprehension”

lista_parzystych_comprehension = [element for element in range(2, 21, 2)]
print(lista_parzystych_comprehension)
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
lista_parzystych_comprehension2 = [element for element in range(2, 21) if (element % 2) == 0 ]
print(lista_parzystych_comprehension2)
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
lista_parzystych_comprehension3 = [element for element in range(2, 21) if not (element % 2)]
print(lista_parzystych_comprehension3)
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

Dict comprehension

slownik = {'Adam': 'Audi', 'Tomek': 'BMW', 'Kasia': 'Citroen'} # doctest: +SKIP

Set comprehension

zbior = {i**2 for i in range(5)}
print(zbior)
{0, 1, 4, 9, 16}

Zadania

Pierwsze

  • Znajdz 20 liczb podzielnych jednocześnie przez 2 i 5

Drugie

  • Stwórz mapowanie (dict comprehension)

    • klucz to liczba, wartość to kolejne litery z alfabetu,

    • {0: 'A', 1: 'B', 2: 'C', 3: 'D'}

Hint

Spójrz na tablicę ASCII

  • Da się konwertować liczbę na literę,

  • da się użyć funkci chr() google

Trzecie

  • mając listę dat w pliku

  • Przetwórz plik wydobywająć jedynie czas (list comprehension) * na podstawie tej listy - utwórz listę, gdzie zdarzenie nastąpiło w 19 sekundzie

Funkcje

  • Daje możliwośc reużywalności kodu,

  • Ułatwia śledzenie jego używania,

  • Bardziej logiczna struktura kodu niz linnia po linni

Poniżej definicja funkcji

def funkcja():
    """"Docstring dokuentujacy funkcje - definicja"""

    print('To jest funkcja')

# "Uruchomienie" funkcji
funkcja()
To jest funkcja

Funkcja z parametrami

def suma_trzech_liczb(a, b, c):
    """Prosta funcka zliczająca 3 liczby"""

    print(a + b + c)

wynik = suma_trzech_liczb(3, 5, 8)
print(wynik)
16
None
def suma_czterech_liczb(a, b, c=0, d=0):
    """Prosta funkcja zliczająca 4 liczby"""

    return (a + b + c + d)

print(suma_czterech_liczb(3, 5))
print(suma_czterech_liczb(3, 5, 8))
print(suma_czterech_liczb(3, 5, 8, 16))
8
16
32

Args

def suma_wielu_liczb(wyswietl, *liczby):
    suma = 0

    for liczba in liczby:
        suma += liczba

    if wyswietl:
        print('Suma wynosi {}'.format(suma))
    return suma

wynik = suma_wielu_liczb(True, 1, 2, 3, 4, 5, 6, 7)
print(wynik)
Suma wynosi 28
28

Kwargs

def suma_zarobkow(**kwargs):
    """sumuje wszystkie osoby"""

    suma = 0

    for czlowiek, zarobki in kwargs.items():
        suma += zarobki
    return suma

print(suma_zarobkow(Adam=3000, Tomek=2500, Kasia=4320))
9820

Zadania

Pierwsze

  • Nie użytkownik poda swój wiek, sprawdź czy jest pełnoletni,

  • Niech użytkownik poda liczbę, sprawdź czy liczba ta jest int czy float

Drugie

  • Stwórz prostą funkcję która będzie sprawdzała siłę hasła (własny algorytm)

  • Hasło może być przynajmniej 6 literowe, maksymalnie 9

  • Hasło jest tyle mocniejsze, gdy:

    • Posiada wielkie litery,

    • Posiada liczbę,

    • Posiada znak specjalny (możesz sam zdefiniować listę specjalną np. ['_', '*', '&']

Trzecie

  • Zmodyfikuj kod na liczenie BMI - tak aby była to teraz funkcja, która dodatkowo przyjmuje

    • Imię,

Czwarte

  • Napisz funkcje dane_zarobkow(dzial, statystyki=True, *args) która dla podanego dzialu zwróci średnią zarobków działu - zaokrąglij do pełnych złotówek

  • Dodatkowo gdy flaga statystyki jest wlączona funkcja opisze więcej statystyk:

    • Średnią,

    • Medianę (własna funkcja),

    • Minimalna wartosc,

    • Maksymalną wartość

Hint

W celu obliczenia mediany można napisać funkcję. Można także wykorzystać rozwiązanie z bibliotek

Wyjątki

  • W przypadku wykonania niedozwolonej operacji,

  • W sytuacjach gdy zasób jest dla nas niedostępny - np. niewystarczające uprawnienia / za mało pamięci itp.

Syntax Errors

>>> while True print('Hello world')
File "<stdin>", line 1
while True print('Hello world')
                ^
SyntaxError: invalid syntax

Key Errors

stolice = {"Francja": "Paryz", "Niemcy":"Berlin", "Polska":"Warszawa", "Czechy":"Praga"}
stolice["USA"]

KeyError: 'USA'

Attribute error

  • Gdy operacja niedostępna

"Hello Wordl".append('!')

Indentation Error

def testfunc():
print('Hello ;)')
 print('My name is:')

File "<ipython-input-4-9cd3c6fb52a1>", line 3
 print('My name is:')
 ^
IndentationError: unexpected indent

ModuleNotFoundError

import not_existing_module

ModuleNotFoundError: No module named 'not_existing_module'

Tablica hierarchi wyjątków w Python.

IndexError

uczestnicy = ['Kasia', 'Adam', 'Tomek']
uczestnicy[6]

IndexError: list index out of range

Obsługa wyjątków

for i in range(3, -3, -1):
 try:
     print('Próba dzielenia przez {}'.format(i))
     3 / i
 except ZeroDivisionError:
     print('Pomijam, nielegalna operajca !!!')

 finally:
     print('Koniec obsługi')
Próba dzielenia przez 3
Koniec obsługi
Próba dzielenia przez 2
Koniec obsługi
Próba dzielenia przez 1
Koniec obsługi
Próba dzielenia przez 0
Pomijam, nielegalna operajca !!!
Koniec obsługi
Próba dzielenia przez -1
Koniec obsługi
Próba dzielenia przez -2
Koniec obsługi

Podniesienie wyjątku

def generate_report(input_data, outputfile):
    raise NotImplementedError('Function development still in progress')

NotImplementedError: Function development still in progress

Zadania

Pierwsze

  • Masz listę uczestników

    • uczestnicy = [“Kasia”, “Adam”, “Tomek”]

  • Obsłuż sytację w której

    • Wydobywany jest elemnt z listy o indeksie 5

    • Nastąpi

Obsłuż wy

Iteratory

  • Lazy evaluation,

  • Oszczędne pamięciowo,

  • Używane są w wielu miejscach

    • open,

    • zip,

    • enumerate,

    • reversed

from typing import Iterable
print(issubclass(range, Iterable))
True

Hint

Podobnie można sprawdzić inne typy tj. list, string

from typing import Iterable, Iterator

print(isinstance(range(10), Iterable))
print(hasattr(range(10),'__iter__'))
print(callable(range(10).__iter__))
print(isinstance(iter([1,2]) , Iterator))
True
True
True
True

Iteratoru vs listy

# nie zużywa pamięci - iteruje w locie
for i in ( i ** 2 for i in range(10**8)):
    print(i)
# zużywa dużo pamięci

lista = [ i ** 2 for i in range(10**8)]

Hint

Porównaj procesy dla listy oraz generatora przy użyciu ps aux PID Dodatkowo możesz użyć funckji linuxowej watch -d -n 0.1

Definiowanie iteratorów

class Numbers:
    def __iter__(self):
        self.value = 1
        return self

    def __next__(self):
        value = self.value
        self.value += 1
        return value

numbers = Numbers()
my_iter = iter(numbers)

print(next(my_iter))
print(next(my_iter))
print(next(my_iter))
1
2
3

Zip

from typing import Iterable, Iterator

za = zip([1,2,3], ['a', 'b', 'c'])
print(isinstance(za, Iterable))
print(isinstance(za, Iterator))
True
True

Zadania

Pierwsze

  • Mamy listę wydatki w poszczególnych dniach tygodnia

    • wydatki = [11.25, 18.0, 20.0, 10.75, 9.50]

  • Wypisz (bez użycia range / len) google

    • “Koszt parkingu nr 1: 11.25”

    • “Koszt parkingu nr 2: 18.00”

Hint

Można wykorzystać słowo kluczowe enumerate

Generatory

  • Lazy evaluation,

  • Oszczędne pamięciowo

import collections, types

print(issubclass(types.GeneratorType, collections.Iterator))
True

Note

Generator jest Iteratorem, lecz Iterator nie jest Generatorem !

Wyrażenie jako generator

g = (n for n in range(20) if not n % 2) # tylko parzyste !

for x in g:
    print(x)

Funkcja jako generator

def simple_gen():
    yield 5
    yield 10
    yield 15

s = simple_gen()

print(next(s))
print(next(s))
print(next(s))
5
10
15
# już nie ma elementów aby przeiterować
print(next(s))

StopIteration:
def new_range(start=0, stop=None, step=1):
    i = start

    if stop is None:
        while True:
            yield i
            i += step
    else:
        while i < stop:
            yield i
            i += step

g = new_range(2, 5)

print(next(g))
print(next(g))
2
3

Note

Generatory to funkcje produkujace kolejne wartosci. Gdy iteratory to obiekty używające metody next()

Zadania

Pierwsze

  • Utwórz generator, który generuje wartości będące 3 krotnością wartości od 0 do 20

Trzecie

  • Wykorzystując plik z zadnia z list comprehension

  • Ściągnij plik przy użyciu pythona

Hint

  • Można użyć biblioteki: urllib

  • Można użyć domyślnej funcki open oraz readline

  • Oczyść plik,

  • Napisz generator konwertujący datę w tekscie na format datowy

  • Jako, że w trakcie generowania logów mieliśmy źle ustawiony zegar - musimy dodać jedną godzinę

Hint

W pakiecie datetime jest timedelta

Biblioteka standardowa

Biblioteka standardowa

Pickling

Proces serializacji danych binarnych do postaci pliku

Dump

godziny = ['Tue Mar 29 23:40:17 +0000 2016', 'Tue Mar 29 23:40:19 +0000 2016']

plik_zapis = open('/Users/kamil/daty.pickle', 'wb') # write/binary
pickle.dump(godziny, pliczek)

Load

Hint

Metoda load zamiast dump

Warning

W przypadku Linuxa lub Windows są inne ścieżki.

Zadania

Pierwsze

  • Ściągnąć podany plik

  • Przetworzyć daty (stringi) do formatu z paczki datetime, w przypadku gdy

Hint

Aby ustalić format można zajrzeć do dokumentacji

  • Zapisać pickle po przetworzeniu

  • Odczytać pickle do innej zmiennej - sprawdzić

Operacje plikowe

Odczytywanie plików

file = 'plik.txt'

Czytanie linnia po linni

with open(r'../plik.txt') as plik_deskryptor:
    lines = deskryptor_pliku.readlines()

Zapis

with open(r'/tmp/iris.csv', mode='w') as plik_deskryptor:
    plik_deskryptor.write('hello')

Context manager

with open(r'plik.txt') as deskryptor_pliku:
     for linia in deskryptor_pliku:
         print(linia)

Wyrażenia regularne

Import

>>> import re

Zastosowania

  • Przetwarzanie tekstu,

    • Znajdowanie wzorców,

    • Oczyszczanie danych

  • Walidacja poprawności danych

Funkcje w pakiecie re

funkcja

znaczenie oraz użycie

Wynik

re.match

Czy pasuje re.match(r"(\d+)\.(\d+)", "24.1632")

True/False

re.search

Pierwsze położenie re.search('(?<=abc)def', 'abcdef')

re.split

Dzieli po seperatorze re.split(r'\W+', 'a, b, c')

Lista

re.findall

Znajdź wszystkie wystąpienia re.findall('\w+', "A B")

Lista

re.finiter

Znajdź wszystkie wystąpienia re.finditer('\w+', "A B")

Iterator

Klasy znaków

klasa

znaczenie

.

Dowolny znak

^

Początek linni

$

Koniec linni

Zero lub więcej wystąpień

Jeden lub więcej wystąpień

?

Jeden lub zero wystąpień

{n}

N wystąpięń

{n, m}

Ilość wystąpięń w przedziale od n do m

d

Grupa liczbowa synonim [0-9]

D

Anty grupa liczbowa synonim [^0-9]

w

Grupa “słowna” - synonim [a-zA-Z0-9_]

W

Anty grupa “słowna” - synonim [^a-zA-Z0-9_]

s

Grupa białych znaków - synonim [rntfv]

[abc]

Grupa znaków a, b lub c

[a-z]

Znaki w zakresie od a do z

()

Grupa

Zadania

Pierwsze

  • Stwórz funkcję sprawdz_ip

    • Funkcja będzie sprawdzać czy IP jest poprawne,

    • Przetestuj funkcję na slowniku hostow

 {
     '127.0.0.1': {'poprawny': None},
     '8.8.8.8': {'poprawny': None},
     'x.x.x.x': {'poprawny': None}
 }

* W miejsce ``x.x.x.x`` wstaw adres hosta w swojej sieci,
* Zaktualizuj flagę ``poprawny``

Hint

Można użyć poniższego wyrażenia regularnego, lub znaleźć / stworzyć bardziej dokładne wyrażenie ^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$

Drugie

  • Stwórz funkcję sprawdz_email

    • Funkcja będzie sprawdzać czy email jest poprawny

Trzecie

  • Używając biblioteki requests

    • Ściągnij zawartość strony

  • Wydobądź wszystkie tagi html,

  • Wydobądź słowa - które człowiek jest w stanie przeczytać

Czwarte

  • Używając biblioteki collections

    • Wylicz wystąpienia słów z punktu Trzeciego,

    • Wyświetl top 10 najczęstszych słów - wnioski ?,

    • Wyświetl top 70 najczęstszych słów - wnioski ?

Zasoby

  • Regex Expressions 101 - strona

  • Regular Expressions Cookbook by Steven Levithan, Jan Goyvaerts - książka

Programowanie obiektowe

Programowanie obiektowe

Zadania

Pierwsze

  • Stworz klase pojazd_mechaniczny, który będzie dziedziczyl po pojazdach,

  • Przy tworzeniu pojazdu mech. Pytamy o numer VIN

  • Dodaj właściwości:

  • Ilosc paliwa

  • Spalanie na 100 km

  • Dodaj własciwosc (property)

  • Dodaj metode liczaca spalanie na 100 km na MPG (statyczna metoda)

Drugie

  • Stworz klase Server posiadajaca:

    • Nazwe,

    • Ip,

    • Uzyj importu os,

    • Stworz metode pinguj (uzyj os – opal ping systemowy),

    • Zapisuj historie pingów - data i czy sie udalo,

    • Stworz liste hostow do pingowania [ ‘127.0.0.1’, …..],

    • Wyswietl komunikat czy się udalo zrobic pinga

Hint

Biblioteka __pathlib__ (std). Klasa `PurePath:

Hint

Biblioteka `ldap3

Programowanie sieciowe

Web api - Django

Stworzenie środowiska wirtualnego

python -m venv venv
source venv/bin/activate

Instalacja

pip install django
pip install djangorestframework # pamietaj o dodaniu 'rest_framework', do settings.py - INSTALLED_APPS
pip install django-extensions # pamietaj o dodaniu 'django_extensions', do settings.py - INSTALLED_APPS
pip install markdown       # Markdown support for the browsable API.
pip install django-filter  # Filtering support - pamietaj o dodaniu do settings.py 'django_filters' - INSTALLED_APPS

Utworzenie pliku zależności

pip freeze > requirements.txt

Utworzenie nowego projektu

django-admin startproject servermonitoring
cd servermonitoring
python manage.py migrate
python manage.py runserver

Utworzenie nowej aplikacji

django-admin startapp api

Sprawdzenie w przeglądarce

  • Chrome/Postman pod adres http://127.0.0.1:8000/

  • Curl http://127.0.0.1:8000/

Dostosowanie ustawień

Tip

podejrzyj plik manage.py np. poprzez polecenie cat manage.py można tam znaleźć w jaki sposób django jest uruchamiane

zmień ustawienia w settings.py

vim servermonitoring/settings.py

Hint

można to zrobić np. poprzez uruchomienie vim servermonitoring/settings.py

albo bezpośredni w pyCharm

# servermonitoring/settings.py

INSTALLED_APPS = [
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django_filters',
 'django_extensions',
 'rest_framework',
 'api'
]

Utworzenie testów

# api/tests.py

from django.test import TestCase
from rest_framework import status

from api.models import Server

class ServerModelTestCase(TestCase):
    """Klasa testów modelu Server"""

    def setUp(self):
        """Definicja wartosci startowych"""

        self.server = Server(address='127.0.0.1')

    def test_model_repr(self):
        self.assertEqual("<Server address: 127.0.0.1>", repr(self.server))

    def test_model_str(self):
        self.assertEqual("Server o adresie: 127.0.0.1", str(self.server))

Odpalenie testu

python manage.py test

Tworzenie modeli

from django.db import models

class Server(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    location = models.CharField(max_length=100, null=True, blank=True, default='')
    available = models.BooleanField(default=False)
    address = models.GenericIPAddressField()
    admin_contact = models.EmailField(max_length=70, null=True, blank=True)
    admin_phone = models.CharField(max_length=70, null=True, blank=True, default='')

    def __repr__(self):
        return "<{} address: {}>".format(self.__class__.__name__, self.address)

    def __str__(self):
        return "{} o adresie: {}".format(self.__class__.__name__, self.address)

Utworzenie oraz uruchomienie migracji

python manage.py makemigrations
python manage.py migrate

Sprawdzenie kodu sql migracji

python manage.py sqlmigrate api 0001

Odpalenie testu po dodaniu modelu

python manage.py test

Dodanie testu widoku

# api/tests.py
# ............

from django.test import TestCase
from rest_framework import status
from api.models import Server
from django.urls import reverse

class ViewServerTestCase(TestCase):
    """Test dla widoku serwera"""

    def test_create_server(self):
        """Sprawdzimy czy mozna utworzyc serwer (post)"""

        url = reverse('servers')
        data = {"location": "office", "address": "127.0.0.1"}

        response = self.client.post(url, data, format="json")

        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(len(response.data), 1)

    def test_view_server_list(self):
        """Sprawdzimy czy pobierze wlasciwa ilosc serverow"""

        url = reverse('servers')

        response = self.client.get(url, format="json")
        self.assertEqual(response.status_code, status.HTTP_200_OK)

Serializer

# api/serializers.py

from rest_framework import serializers

from .models import Server

class ServerSerializer(serializers.ModelSerializer):
    class Meta:
        model = Server
        fields = '__all__' # albo fields = ('location', 'address',)

Dodanie widoku

# api/views.py

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

from .serializers import ServerSerializer
from .models import Server

class ServerList(APIView):
    """Lista serwerow"""

    serializer_class = ServerSerializer

    def get_queryset(self):
        queryset = Server.objects.all()
        location = self.request.query_params.get('location', None)

        if location is not None:
            queryset = queryset.filter(location__icontains=location)
        return queryset

    def get(self, request, format=None):

        servers = self.get_queryset()
        serializer = ServerSerializer(servers, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = ServerSerializer(data=request.data)

        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Dodanie urls

from django.contrib import admin
from django.urls import path

from api import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('servers/', views.ServerList.as_view(), name='servers')
]

Metody

  • Get

  • Post

  • Put

  • Delete

Kody HTTP

  • 200 - powodzenie. Request poprawy. Odpowiedź poprawna.

  • 400 - zły request. Źle sformuowany request / problemy z autentykacją.

  • 403 - dostęp zabroniony,

  • 404 - nie ma takiej strony,

  • 500 - błąd wewnętrzny serwera. Najczęściej gdy popełniliśmy jakiś błąd w kodzie np. w django.

Requesty

Odpowiedzi (response)

Settingsy

Widok

Migracja

Hint

Aby podejrzeć migracje można użyć: python manage.py showmigrations

Orm

Django extensions

python manage.py show_urls
python manage.py shell_plus # lepsza konsola - ipython
python manage.py runserver_plus # server

Zadania

Zero

  • Napraw test,

  • Dodaj do testu sprawdzanie daty - stworzenia wpisu

Pierwsze

  • Stworz 4 hosty - każdy w inny sposób

    • Przez stronę web,

    • Przez request z postmana,

  • Stwórz model, który:

    • Będzie przetrzymywał datę

Pierwsze

  • Stwórz endpoint (POST), który:

    • Będzie

Drugie

Rest

Zadania

Requesty

Odpowiedzi (response)

Kody HTTP

  • 200 - powodzenie. Request poprawy. Odpowiedź poprawna.

  • 400 - zły request. Źle sformuowany request / problemy z autentykacją.

  • 500 - błąd wewnętrzny serwera. Najczęściej gdy popełniliśmy jakiś błąd w kodzie np. w django.

Pierwsze

Drugie

Bazy danych

jjj

Zasoby

Pierwsze

Drugie

Gniazda / sockety

Adres IP

Hint

biblioteka wbudowana ipaddress

Hint

Jak sprawdzić nasłuchujące porty ?

netstat -nap tcp | grep -i "listen"

Testowanie jednostkowe

Biblioteka unittest

Programowanie zaawansowane

Dekoratory

Cel

Dekoratory pozwalają rozszerzyć funkcjonalność funkcji lub klasy. Dektoratory są funkcjami które “opakowują” inne funkcje lub klasy.

Przypadki użycia

  • Pamięć podręczna - (Cache),

  • Sprawdzanie argumentów,

  • Logowanie,

  • Rejestracja,

  • Weryfikacja

Definicja

def decorator_function(origin_function):
    def wraper_function():
        print('przed funkcją o nazwie {}'.format(origin_function.__name__))
        return origin_function()
    return wraper_function

@decorator_function
def main_function():
    print('główna funkcja')

main_function()
przed funkcją o nazwie main_function
główna funkcja

Definicja gdy funkcja ma parametry (*args / **kwargs)

def decorator_function(origin_function):
    def wraper_function(*args, **kwargs):
        print('przed funkcją o nazwie {}'.format(origin_function.__name__))
        return origin_function(*args, **kwargs)
    return wraper_function


@decorator_function
def hello_function(imie, nazwisko):
    print('Czesc jestem {} {}'.format(imie, nazwisko))

hello_function("Adam", "Nowak")
przed funkcją o nazwie hello_function
Czesc jestem Adam Nowak

Sparametryzowany dekorator

Przykład

Note

hasattr opisane jest w Include/abstract.h

Note

hasattr zaimplementowane jest w Objects/object.c

Użycie

Tip

podejrzyj plik manage.py np. poprzez polecenie cat manage.py można tam znaleźć w jaki sposób django jest uruchamiane

zmień ustawienia w settings.py

Hint

można to zrobić np. poprzez uruchomienie vim servermonitoring/settings.py

albo bezpośredni w pyCharm

Zadania

Zero

Wzorzec projektowy - Proxy/Pełnomocznik

  • Klasa proxy to klasa która może ograniczać dostęp do następnej klasy

Przypadki użycia

  • Względy bezpieczeństwa

Diagram UML

Hashe

Przykład z hashem frozenseta

Python internals

Pozyskanie kodu

  • Utworzenie forka na githubie

Kompilacja

Hint

Najlepiej skompilować z opcjami tls/ssl

W przeciwnym wypadku pip będzię zgłaszał poniższy problem. Can't connect to HTTPS URL because the SSL module is not available

Poniżej polecenie do konfigurowania oraz kompilacji

./configure --with-pydebug --with-openssl=$(brew --prefix openssl) && make -j
# Kompilacja

make -j2 # 2 joby

Hint

Parametr -j określa ilość “jobów” odpalonych dla kompilacji. Więc możemy uzyć takiej kombinacji na Macu make -j$(sysctl hw.ncpu | grep -Eo "\d+")

Aby używać tymczasowo naszego skompilowanego pythona musimy wskazać go w ścieżce path

PATH="/usr/local/bin:$PATH"
export PATH

Po tej operacji python3 wskazywać będzie na naszą skompilowaną wersję

Caution

Zmienna PATH będzie zmieniona jedynie w trakcjie sesji terminala.

Instalacja

make altinstall

Hint

Aby zaistalować python3 na stałe musimy zrobić make install zamiast altinstall

Wartości predefiniowane - Makra kompilatora

Wyświetlenie wszystkich predefiniowanych wartości

gcc -dM -E - </dev/null

Zmiany w module os

Powiedzmy, że chcielibyśmy zmienić zachowanie metod z modułu os.

Założenia

  • listdir będzie pokazywał pliki/foldery które nie są ukryte (Wszystkie pliki/foldery z kropką na początku będą pomijane)

Utworzenie gałęzi (branch)

Aby utworzyć gałąż z naszymi zmianami:

git checkout -b oslib_changes

Uruchomienie testów

Aby upewnić się, że wszystkie testy przechodzą.

make test

Wyszukiwanie kodu

Domyślnie moduły znajdują się w: Lib/. Do podejrzenia na github

Jako że używamy systemu posix (mac). W kodzie mamy sprawdzenie tego faktu w linni 48 os.py.

  • Linia 48 - sprawdzenie systemu

  • Linia 51 - załadowanie wszystkiego z posix

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
if 'posix' in _names:
 name = 'posix'
 linesep = '\n'
 from posix import *
 try:
     from posix import _exit
     __all__.append('_exit')
 except ImportError:
     pass
 import posixpath as path

 try:
     from posix import _have_functions
 except ImportError:
     pass

 import posix
 __all__.extend(_get_exports_list(posix))
 del posix
  • Po wyszukaniu listdir niczego nie znaleziono,

  • Prawdopodobnie listdir jest w innym module - np. posix.

Hint

Biblioteka posix jest napisana w niskopoziomowy sposób język C Jego prawdziwa nazwa to: posixmodule.c

  • Linia 2 - nazwa funkcji dostępna w debugerze,

  • Linia 8 - sprawdzenie czy jest dostępna funkcja fdopendir - funkcja Unixowa

Hint

Można sprawdzić tą funkcję przy użyciu man fdeopendir

Zadania

  • Zmienić

python3 range vs python2 range vs python2 xrange

9999999999999999999 - 21 in range(1000000000, 9999999999999999999, 3)
# w python 3 szybkie

Python 3 bierze pod uwagę __start__, __stop__ oraz __step__

9999999999999999999 - 21 in xrange(1000000000, 9999999999999999999, 3)
# w python 2 wolne

analiza kodu

Język

Case study

Todo

Zbadać zachowanie w if-ie == oraz =

Algorytmy

Drzewo

Definicja drzewa

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
class Node:
 def __init__(self, value):
     self.value = value
     self.left = None
     self.right = None
 def insert(self, value):
     if value <= self.value:
         if self.left is None:
             self.left = Node(value)
         else:
             self.left.insert(value)
     else:
         if self.right is None:
             self.right = Node(value)
         else:
             self.right.insert(value)
 def __repr__(self):
     return '<Node: value: {}'.format(str(self.value))
 def search(self, value):
     if self.value == value:
         return True
     elif value < self.value:
         if isinstance(self.left, type(None)):
             return False
         if self.left.value == None:
             return False
         else:
             return self.left.search(value)
     else:
         if isinstance(self.right, type(None)):
             return False
         if self.right.value == None:
             return False
         else:
             return self.right.search(value)

 def __contains__(self, value):
     return self.search(value)


 def in_order_traversal(self):
     if self.left != None:
         self.left.in_order_traversal()
     print(self.value)

     if self.right != None:
         self.right.in_order_traversal()
 def get_height(self):
     height = 1
     if not isinstance(self.left, type(None)):
         height_left = self.left.get_height()
     else:
         height_left = 0
     if not isinstance(self.right, type(None)):
         height_right = self.right.get_height()
     else:
         height_right = 0

     return height + max(height_left, height_right)
 def __len__(self):
     return self.get_height()

 a = Node(6)
 len(a)

Hint

tree

Linked list

Linked lists

Testy

  • Reprezentacja,

  • Wstawianie wartości na danej pozycji w liscie,

  • pozycja “0”,

  • pozycja n

  • Odwracanie listy

Implementacja testów

[25]:
## Implementacja testów
import unittest

class TestLinkedList(unittest.TestCase):
    """Test linked list"""
    def setUp(self):
        self.linked_list = Linked(1)
        linked2 = Linked(2)
        linked3 = Linked(3)
        linked2.next = linked3
        self.linked_list.next = linked2

    def test_repr(self):
        self.assertRegex(repr(self.linked_list), '<Linked with value:.*')
    def test_insert_at_position_0(self):
        new_linked = self.linked_list.insert_at(0, 4)

        cur = new_linked
        results = []
        while cur:
            results.append(cur.data)
            cur = cur.next
        self.assertEqual(sorted(results), [1, 2, 3, 4])
        self.assertEqual(results, [4, 1, 2, 3])

    def test_insert_at_postion_1(self):
        self.linked_list.insert_at(1, 4)
        cur = self.linked_list
        results = []
        while cur:
            results.append(cur.data)
            cur = cur.next
        self.assertEqual(results, [1, 4, 2, 3])

    def test_insert_at_position_2(self):
        self.linked_list.insert_at(2, 4)
        cur = self.linked_list
        results = []
        while cur:
            results.append(cur.data)
            cur = cur.next
        self.assertEqual(results, [1, 2, 4, 3])

    def test_insert_at_position_3(self):
        self.linked_list.insert_at(3, 4)
        cur = self.linked_list
        results = []
        while cur:
            results.append(cur.data)
            cur = cur.next
        self.assertEqual(results, [1, 2, 3, 4])

Odpalenie testów

[26]:
if __name__ == '__main__':
    unittest.main(argv=['first-arg-is-ignored'], exit=False)
.....
----------------------------------------------------------------------
Ran 5 tests in 0.008s

OK

Implementacja list

[20]:
class Linked:
    def __init__(self, data):
        self.data = data
        self.next = None
    def __repr__(self):
        return '<{} with value: {}'.format(self.__class__.__name__, self.data)

    def insert_at(self, pos, data):
        if self.data == self.next == None:
            self.data = data
        cur = self
        tmp_pos = 0

        if pos == 0:
            el = Linked(data)
            el.next = self
            return el

        while cur and tmp_pos < pos:
            tmp_pos += 1
            if tmp_pos == pos:
                el = Linked(data)
                el.next = cur.next
                cur.next = el
            else:
                cur = cur.next

        return self
[1]:
class Element:
    def __init__(self, val):
        self.val = val
        self.next = None
        self.len = 1
    def insert(self, val):
        cur = self
        while cur.next is not None:
            cur = cur.next
        cur.next = Element(val)
        self.len += 1

    def __repr__(self):
        next_val = None
        if hasattr(self.next, 'val'):
            next_val = self.next.val
        return '<{} {} long with value: {} and next element {}'.format(self.__class__.__name__, self.len, self.val, next_val)
    def insert_first(self, val):
        head = Element(val)
        head.next = self
        self.len += 1

        return head
    def deleteNode(self, position):
        self[position-1].next = self[position+1]
        self.len -= 1
        return self[position]

    def __iter__(self):
        self.n = 0
        self.cur = self

        return self

    def __next__(self):
        if self.n < self.len:
            ret_val = self.cur
            self.n += 1
            self.cur = self.cur.next
            return ret_val
        else:
            raise StopIteration

    def __getitem__(self, index):
        cur_iter = iter(self)
        cur_item = None

        for i, item in enumerate(cur_iter):

            if i < index:
                continue
            elif i == index:
                cur_item = item
            else:
                break
        return cur_item


    def __len__(self):
        return self.len
[ ]:

Stos

Implementacja testów

[2]:
import unittest

class TestStack(unittest.TestCase):
    def setUp(self):
        self.stack = Stack()
        self.stack.values = [1, 2, 3]
    def test_pop(self):
        result = self.stack.pop()
        self.assertEqual(result, 3)
        result2 = self.stack.pop()
        self.assertEqual(result2, 2)
    def test_push(self):
        self.stack.push(9)
        result = self.stack.pop()
        self.assertEqual(result, 9)

Implementacja stosu

[3]:
class Stack:
    def __init__(self):
        self.head = None
        self.values = []
    def push(self, value):
        self.values.append(value)
        self.head = value
    def pop(self):
        ret = self.values.pop()
        return ret

Uruchomienie testów

[4]:
if __name__ == '__main__':
    unittest.main(argv=['first-arg-is-ignored'], exit=False)
..
----------------------------------------------------------------------
Ran 2 tests in 0.003s

OK
[ ]: