1/60
Czym jest Python?
Slajd przedstawia genezę, filozofię projektową oraz cechy architektoniczne języka Python jako uniwersalnego narzędzia programistycznego.

Python: przyjazny język programowania

  • Geneza i twórca: język stworzony przez Guido van Rossuma, wydany po raz pierwszy w lutym 1991 roku w Holandii.
  • Czytelność i prostota: filozofia The Zen of Python stawiająca przejrzystość kodu i zwięzłość składni ponad skomplikowane konstrukcje.
  • Wieloparadygmatowość: pełne wsparcie dla programowania strukturalnego, obiektowego (OOP) oraz funkcyjnego.
  • Zarządzanie pamięcią: automatyczne odśmiecanie pamięci (Garbage Collection) oraz dynamiczne, lecz silne typowanie danych.
Język Python: wysokopoziomowy, interpretowany język programowania ogólnego przeznaczenia o dynamicznym i silnym typowaniu. Charakteryzuje się czytelną składnią opartą na wcięciach blokowych (off-side rule) oraz bogatą biblioteką standardową określaną mianem 'batteries included'.
+------------------+
|                  |
|   Witaj w        |
|   Świecie        |
|   Pythona!       |
|                  |
|   print("Hello!")|
|                  |
+------------------+
            
2/60
Gdzie używamy Pythona?
Slajd omawia kluczowe dziedziny inżynierii informatycznej, w których Python jest wiodącym językiem programowania.

Obszary zastosowań technologii

  • Automatyzacja i DevOps: pisanie skryptów administracyjnych, orkiestracja serwerów (Ansible) oraz zarządzanie chmurą.
  • Sztuczna inteligencja i Data Science: niekwestionowany standard w uczeniu maszynowym (TensorFlow, PyTorch, scikit-learn) i analizie danych.
  • Programowanie sieciowe i webowe: tworzenie skalowalnych serwisów internetowych i interfejsów API w frameworkach Django, Flask i FastAPI.
  • Cyberbezpieczeństwo i testy: skrypty audytowe, automatyzacja testów penetracyjnych oraz analiza złośliwego oprogramowania.
Ekosystem Pythona: zbiór powiązanych bibliotek, frameworków, narzędzi deweloperskich oraz globalnej społeczności skupionej wokół Python Software Foundation (PSF), umożliwiający wszechstronne zastosowanie języka w nauce i przemyśle.
+-------------------------+
|   PYTHON W DZIAŁANIU    |
+-------------------------+
| [x] Tworzenie skryptów |
| [x] Automatyzacja IT    |
| [x] Analiza plików      |
| [x] Praca z siecią      |
| [x] Przetwarzanie danych|
+-------------------------+
            
3/60
Jak zainstalować Pythona?
Slajd przedstawia proces instalacji interpretera CPython w systemach Windows, Linux oraz macOS wraz z konfiguracją ścieżki systemowej PATH.

Środowisko uruchomieniowe i instalacja

  • Dystrybucja oficjalna (python.org): pobranie oficjalnego instalatora ze strony Python Software Foundation.
  • Dodanie do ścieżki PATH: kluczowe zaznaczenie opcji 'Add python.exe to PATH' podczas instalacji w systemie Windows.
  • Natywna obecność w Linuksie: większość dystrybucji (Ubuntu, Debian, Fedora) posiada preinstalowany interpreter Python 3.
  • Weryfikacja wersji w konsoli: sprawdzenie poprawności instalacji poleceniem python3 --version lub py --version.
Ścieżka systemowa PATH: zmienna środowiskowa systemu operacyjnego zawierająca uporządkowaną listę katalogów, w których powłoka poszukuje programów wykonywalnych, gdy użytkownik wpisze polecenie bez pełnej ścieżki dyskowej.
# Windows - otwórz CMD lub PowerShell
C:\> python --version
Python 3.11.4

# Linux/macOS - otwórz terminal
$ python3 --version
Python 3.11.4

# Uruchomienie interaktywnego Pythona
$ python3
>>> print("Witaj!")
Witaj!
>>> exit()
4/60
Tworzymy pierwszy skrypt!
Slajd demonstruje utworzenie i strukturę pierwszego programu w Pythonie wypisującego tekst w oknie terminala.

Struktura programu i rozszerzenie .py

  • Rozszerzenie pliku (.py): standardowe rozszerzenie plików źródłowych Pythona interpretowanych przez środowisko uruchomieniowe.
  • Funkcja wbudowana print(): podstawowe polecenie wypisujące przekazane argumenty na standardowy strumień wyjściowy (stdout).
  • Brak średników na końcu: instrukcje w Pythonie są rozdzielane znakami nowej linii bez konieczności stosowania średników.
  • Kodowanie UTF-8: kod źródłowy Pythona 3 jest domyślnie interpretowany w międzynarodowym standardzie kodowania UTF-8.
Funkcja print(): wbudowana w jądro języka funkcja wejścia/wyjścia przesyłająca tekstową reprezentację jednego lub wielu obiektów do standardowego strumienia wyjściowego, domyślnie zakończona znakiem nowej linii.
# To jest nasz pierwszy skrypt w Pythonie
# Komentarze zaczynają się od znaku #

print("Witaj świecie!")
print("To jest mój pierwszy program.")
print("Python jest super!")
5/60
Jak uruchamiać skrypty Python?
Slajd przedstawia metody egzekucji kodu: wiersz poleceń, zintegrowane edytory kodu oraz interaktywną pętlę REPL.

Metody uruchamiania i tryb interaktywny REPL

  • Uruchomienie z wiersza poleceń: wywołanie python skrypt.py przekazuje plik źródłowy do sekwencyjnej interpretacji.
  • Tryb interaktywny (REPL): uruchomienie samego polecenia python otwiera interaktywną konsolę Read-Eval-Print Loop.
  • Uruchomienie w VS Code: wygodne wykonywanie i debugowanie kodu jednym kliknięciem za pomocą rozszerzenia Python Extension.
  • Mechanizm Shebang w Linuksie: dodanie linii #!/usr/bin/env python3 na początku pliku pozwala na uruchamianie skryptu jak programu binarnego.
Pętla REPL (Read-Eval-Print Loop): interaktywne środowisko powłoki programistycznej, które odczytuje pojedynczą instrukcję wprowadzoną przez programistę, natychmiast ją ewaluuje, wypisuje wynik i oczekuje na kolejne polecenie.
# Uruchomienie skryptu z pliku
$ python3 moj_skrypt.py
Witaj!
Mój pierwszy skrypt działa!

# Tryb interaktywny - wpisuj kod linijka po linijce
$ python3
>>> 2 + 2
4
>>> print("Cześć!")
Cześć!
>>> nazwa = "Python"
>>> print(f"Witaj, {nazwa}!")
Witaj, Python!
>>> exit()
6/60
Zmienne: skrzynki na dane
Slajd omawia koncepcję zmiennych w Pythonie jako nazwanych referencji do obiektów alokowanych w pamięci operacyjnej.

Tworzenie referencji do obiektów w pamięci

  • Dynamiczna deklaracja: zmienna powstaje automatycznie w momencie pierwszego przypisania wartości operatorem =.
  • Zmienna jako wskaźnik: zmienna nie przechowuje wartości bezpośrednio, lecz referencję (adres) do obiektu w pamięci RAM.
  • Konwencja snake_case: zgodnie ze standardem PEP 8 nazwy zmiennych zapisuje się małymi literami rozdzielanymi podkreśleniami.
  • Czułość na wielkość liter: identyfikatory moja_zmienna oraz Moja_Zmienna reprezentują dwa całkowicie odrębne obiekty.
Referencja do obiektu (object reference): adres pamięci powiązany z nazwą zmiennej, wskazujący na rzeczywisty obiekt danych zaalokowany na stercie wirtualnej maszyny interpretera CPython.
# Tworzenie zmiennych
wiek = 20
imie = "Anna"
jest_studentem = True
wzrost = 1.65

# Wyświetlanie zmiennych
print(wiek)
print(imie)
print(jest_studentem)
print(wzrost)

# Użycie zmiennych
print("Mam na imię", imie)
print("Mam", wiek, "lat")
print("Czy jestem studentem?", jest_studentem)
7/60
Typy danych: liczby
Slajd przedstawia numeryczne typy danych w Pythonie: int o dowolnej precyzji, float oraz operacje arytmetyczne.

Liczby całkowite, zmiennoprzecinkowe i operacje

  • Liczby całkowite (int): w Pythonie 3 typ int charakteryzuje się nieograniczoną precyzją, ograniczoną wyłącznie pamięcią RAM.
  • Liczby zmiennoprzecinkowe (float): reprezentacja liczb rzeczywistych o podwójnej precyzji zgodna ze standardem IEEE 754.
  • Dzielenie zmiennoprzecinkowe (/): zwykły operator dzielenia w Pythonie 3 zawsze zwraca wynik typu float (np. 4 / 2 daje 2.0).
  • Dzielenie całkowite (//) i modulo (%): operator // obcina część ułamkową w dół, a operator % zwraca resztę z dzielenia.
Typ numeryczny int: wbudowana klasa liczb całkowitych w Pythonie implementująca arytmetykę o dowolnej wielkości (arbitrary-precision arithmetic), eliminująca ryzyko klasycznego przepełnienia bufora 32 lub 64-bitowego.
# Liczby całkowite (int)
a = 10
b = 3

# Operacje
print("a + b =", a + b)    # 13
print("a - b =", a - b)    # 7
print("a * b =", a * b)    # 30
print("a / b =", a / b)    # 3.333...
print("a // b =", a // b)  # 3 (część całkowita)
print("a % b =", a % b)    # 1 (reszta)
print("a ** b =", a ** b)  # 1000 (10 do potęgi 3)

# Float - liczby dziesiętne
cena = 19.99
podatek = 0.23
print("Cena z podatkiem:", cena * (1 + podatek))
8/60
Typy danych: tekst (stringi)
Slajd omawia klasę str, niezmienniczość tekstu (immutability), cudzysłowy oraz znaki ucieczki.

Niezmienny ciąg znaków typu str

  • Literały tekstowe: możliwość definiowania tekstu w apostrofach ('...'), cudzysłowach ("...") lub potrójnych cudzysłowach ("""...""").
  • Niezmienność (immutability): raz utworzony obiekt str nie może być zmodyfikowany w miejscu; każda zmiana tworzy nowy obiekt.
  • Indeksowanie i wycinanie: dostęp do znaków od zera (tekst[0]); ujemne indeksy liczą od końca (tekst[-1]).
  • Znaki specjalne (escape characters): sekwencje takie jak \n (nowa linia), \t (tabulacja) oraz surowe łańcuchy znaków (raw strings: r"...").
Niezmienność tekstu (string immutability): właściwość architektoniczna klasy str w Pythonie oznaczająca, że zawartość bufora znaków obiektu nie może ulec zmianie po jego utworzeniu, co gwarantuje bezpieczeństwo w środowiskach wielowątkowych.
# Tworzenie stringów
imie = "Anna"
nazwisko = 'Kowalska'

# Łączenie tekstów
pelne_imie = imie + " " + nazwisko
print(pelne_imie)  # Anna Kowalska

# F-stringi (nowoczesne łączenie)
wiek = 20
print(f"Nazywam się {imie} {nazwisko} i mam {wiek} lat.")

# Metody stringów
print(imie.upper())      # ANNA
print(imie.lower())     # anna
print(len(imie))        # 4

# Indeksowanie (znak po znaku)
print(imie[0])  # A (pierwszy znak)
print(imie[-1]) # a (ostatni znak)
9/60
Typy danych: wartości logiczne
Slajd przedstawia typ bool, stałe logiczne True i False oraz reguły konwersji obiektów na wartości prawdy (truthiness).

Prawda, fałsz i operatory logiczne

  • Typ logiczny bool: podklasa typu int posiadająca dokładnie dwie instancje: True (wartość numeryczna 1) oraz False (0).
  • Operatory logiczne (and, or, not): czytelne słowa kluczowe języka realizujące operacje koniunkcji, alternatywy i negacji.
  • Pojęcie Truthiness: każdy obiekt w Pythonie ma domyślną wartość logiczną: puste kolekcje, zero i None są traktowane jak False.
  • Zastosowanie w warunkach: idiomatyczne sprawdzanie obecności elementów: if lista: zamiast if len(lista) > 0:.
Pojęcie Truthiness (falsy / truthy): wbudowana w Pythona reguła rzutowania dowolnego obiektu na wartość logiczną w instrukcjach warunkowych, gdzie wartości puste (pusty string, pusta lista, liczba zero, None) są ewaluowane jako False, a niepuste jako True.
# Wartości logiczne
czy_jestem_studentem = True
czy_mam_duzo_pieniedzy = False

print(czy_jestem_studentem)  # True
print(czy_mam_duzo_pieniedzy)  # False

# Operatory porównania
x = 10
y = 5

print(x == y)   # False (równe?)
print(x != y)   # True (różne?)
print(x > y)    # True (większe?)
print(x < y)    # False (mniejsze?)

# Operatory logiczne
wiek = 20
ma_dowod = True

# AND - oba warunki muszą być spełnione
print(wiek >= 18 and ma_dowod)  # True

# OR - przynajmniej jeden warunek
print(wiek < 18 or ma_dowod)    # True

# NOT - odwraca
print(not wiek < 18)  # True (bo 20 nie jest < 18)
10/60
Komentarze: dokumentowanie kodu
Slajd omawia techniki dokumentowania programów: komentarze jednoliniowe ze znakiem # oraz łańcuchy dokumentacyjne docstrings.

Komentarze jednoliniowe i docstringi

  • Komentarz jednoliniowy (#): symbol # nakazuje interpreterowi zignorować resztę bieżącego wiersza kodu źródłowego.
  • Łańcuchy dokumentacyjne (docstrings): wieloliniowe literały w potrójnych cudzysłowach umieszczane na początku modułu, klasy lub funkcji.
  • Funkcja help(): automatyczne generowanie dokumentacji technicznej z docstringów za pomocą wbudowanej funkcji help().
  • Czystość kodu: komentowanie dlaczego dane rozwiązanie zostało wybrane, zamiast opisywania oczywistych operacji składniowych.
Docstring (documentation string): specjalny literał tekstowy umieszczony jako pierwsza instrukcja w ciele funkcji, metody, klasy lub modułu, automatycznie przypisywany do atrybutu __doc__ i wykorzystywany przez generatory dokumentacji.
# To jest komentarz jednoliniowy
# Python go zignoruje

print("Ten kod się wykona")

# ---
# KOMENTARZ WIELOLINIOWY
# (używany często jako dokumentacja funkcji)
# ---

"""
To jest komentarz
rozpoczynający się od trzech
podwójnych cudzysłowów.
"""

'''
Albo trzech pojedynczych.
'''

# Praktyczny przykład:
# Pobieram dane od użytkownika
imie = input("Podaj swoje imię: ")

# Sprawdzam, czy użytkownik jest pełnoletni
wiek = int(input("Ile masz lat? "))
11/60
Funkcja print(): wyświetlanie tekstu
Slajd szczegółowo analizuje parametry funkcji print(): sep, end oraz przekierowanie do pliku parametrem file.

Formatowanie wyjścia, separatory i parametry

  • Wypisywanie wielu argumentów: funkcja przyjmuje dowolną liczbę obiektów rozdzielonych przecinkami: print('A', 'B', 'C').
  • Parametr sep (separator): definiuje znak umieszczany pomiędzy wypisywanymi argumentami (domyślnie pojedyncza spacja).
  • Parametr end (koniec linii): określa ciąg dopisywany na końcu wyjścia (domyślnie znak nowej linii \n; end='' zapobiega łamaniu wiersza).
  • Przekierowanie wyjścia (file): możliwość bezpośredniego skierowania tekstu do otwartego pliku lub strumienia sys.stderr.
Parametr sep i end w print(): parametry nazwane funkcji print() kontrolujące zachowanie formatowania wyjściowego: sep modyfikuje łączenie argumentów, a end zarządza znakiem kończącym transmisję w buforze.
# Podstawowe użycie
print("Witaj, świecie!")
print(42)
print(3.14)

# Zmienne
imie = "Anna"
wiek = 20
print(imie)
print("Mam", wiek, "lat")

# F-string - nowoczesne formatowanie
print(f"Nazywam się {imie} i mam {wiek} lat.")

# Separator
print("jabłko", "banan", "pomarańcza", sep=", ")
# Wynik: jabłko, banan, pomarańcza

# Bez nowej linii (end)
print("Punkt 1", end=" -> ")
print("Punkt 2", end=" -> ")
print("Koniec")
# Wynik: Punkt 1 -> Punkt 2 -> Koniec

# Formatowanie liczb
cena = 19.99
print(f"Cena: {cena:.2f} zł")
print(f"Procent: {0.1234:.1%}")
12/60
Funkcja input(): pobieranie danych
Slajd omawia pobieranie danych wejściowych od użytkownika, prompt tekstowy oraz bezwzględną konieczność konwersji ze stringa.

Interakcja z użytkownikiem i konwersja typów

  • Działanie funkcji input(): zatrzymuje wykonanie programu i oczekuje na wpisanie tekstu zakończonego klawiszem Enter.
  • Zawsze zwraca ciąg tekstowy: wartość zwrócona przez input() ma ZAWSZE typ str, nawet gdy użytkownik wpisze same cyfry.
  • Konieczność konwersji: operacje matematyczne wymagają jawnego rzutowania: int(input()) lub float(input()).
  • Obsługa błędów konwersji: wpisanie liter przy próbie konwersji na int wywołuje błąd ValueError, wymagający bloku try/except.
Funkcja input(): wbudowana funkcja Pythona odczytująca pojedynczą linię ze standardowego wejścia (stdin), usuwająca kończący znak nowej linii i zwracająca dane jako obiekt typu str.
# Pobieranie tekstu
print("Jak masz na imię?")
imie = input()
print(f"Cześć, {imie}!")

# Z parametrem - wiadomość w jednej linii
nazwisko = input("Podaj swoje nazwisko: ")
print(f"Razem: {imie} {nazwisko}")

# Pobieranie liczby (konwersja!)
wiek_text = input("Ile masz lat? ")
wiek = int(wiek_text)  # Zamiana tekstu na liczbę
print(f"Za rok będziesz miał {wiek + 1} lat")

# Krótszy zapis (w jednej linii)
cena = float(input("Podaj cenę produktu: "))
podatek = cena * 0.23
print(f"Cena z podatkiem: {cena + podatek:.2f} zł")

# Przykład z kalkulatorem
a = float(input("Podaj pierwszą liczbę: "))
b = float(input("Podaj drugą liczbę: "))
print(f"Suma: {a + b}")
13/60
Operacje na tekstach: metody stringów
Slajd przedstawia kluczowe metody klasy str: lower(), upper(), strip(), replace(), split() oraz join().

Transformacja tekstu, podział i oczyszczanie

  • Zmiana wielkości liter: metody .lower(), .upper(), .capitalize(), .title() zwracające przekształcone kopie tekstu.
  • Usuwanie białych znaków: metoda .strip() usuwa spacje, tabulatory i znaki nowej linii z początku i końca łańcucha.
  • Rozbijanie i scalanie (.split / .join): metoda .split(',') dzieli tekst na listę słów; ' '.join(lista) scala listę w tekst.
  • Wyszukiwanie i sprawdzanie: metody .startswith(), .endswith(), .find() oraz operator in do weryfikacji zawartości.
Metoda split() i join(): fundamentalna para metod przetwarzania tekstu: split() rozbija ciąg znaków na listę podciągów według zadanego separatora, a join() łączy elementy kolekcji w jeden łańcuch z użyciem tekstu bazowego jako spoiwa.
tekst = "  Witaj, Świecie!  "

# Usuwanie białych znaków
print(tekst.strip())  # "Witaj, Świecie!"

# Wielkość liter
print(tekst.upper())
print(tekst.lower())

# Zamiana
print(tekst.replace("Witaj", "Cześć"))

# Sprawdzanie zawartości
print("Witaj" in tekst)   # True
print("Python" in tekst)   # False

# Dzielenie tekstu
zdanie = "Python jest super"
slowa = zdanie.split(" ")
print(slowa)  # ['Python', 'jest', 'super']

# Indeksowanie
print(tekst[0])     # ' ' (pierwszy znak)
print(tekst[1:8])   # 'Witaj, '
print(tekst[-4:-1]) # 'cie'
print(tekst[::2])   # co drugi znak
14/60
Listy: dynamiczne kolekcje danych
Slajd omawia listy w Pythonie (list), ich konstrukcję w nawiasach kwadratowych [], mutowalność oraz indeksowanie elementów.

Struktura, indeksowanie i mutowalność list

  • Konstrukcja listy ([]): uporządkowana, zmienna (mutable) kolekcja elementów dowolnego typu rozdzielana przecinkami.
  • Indeksowanie dwukierunkowe: indeksy dodatnie od 0 do N-1; indeksy ujemne od -1 (ostatni element) wstecz.
  • Złożone wycinki (slicing): składnia lista[start:stop:krok] pozwala na precyzyjne wycinanie podzbiorów (np. lista[::-1] odwraca listę).
  • Kolekcje heterogeniczne: pojedyncza lista może przechowywać liczby, teksty, słowniki, a nawet inne zagnieżdżone listy.
Lista w Pythonie (list): wbudowana, dynamicznie alokowana tablica referencji o zmiennym rozmiarze, zapewniająca szybki dostęp swobodny do elementów o złożoności O(1) na podstawie indeksu liczbowego.
# Tworzenie list
owoce = ["jabłko", "banan", "wiśnia"]
liczby = [1, 2, 3, 4, 5]
pusta = []

print(owoce)
print(liczby)
print(f"Mam {len(owoce)} owoce na liście")

# Dostęp do elementów (indeksowanie od 0!)
print(owoce[0])   # jabłko (pierwszy)
print(owoce[1])   # banan (drugi)
print(owoce[-1])  # wiśnia (ostatni)
print(owoce[-2])  # banan (przedostatni)

# Zmiana elementu
owoce[0] = "gruszka"
print(owoce)

# Sprawdzanie czy element istnieje
print("banan" in owoce)  # True
print("pomarańcza" in owoce)  # False

# Dodawanie elementów
owoce.append("pomarańcza")
print(owoce)
15/60
Operacje na listach: modyfikacja w miejscu
Slajd przedstawia metody modyfikujące listy: append(), extend(), insert(), remove(), pop() oraz sort().

Dodawanie, usuwanie i sortowanie elementów

  • Dodawanie elementów: metoda .append(x) dodaje jeden element na koniec; .extend(kolekcja) dołącza całą kolekcję.
  • Wstawianie w wybranym miejscu: metoda .insert(indeks, x) umieszcza nowy obiekt na wskazanej pozycji, przesuwając resztę w prawo.
  • Usuwanie elementów: metoda .remove(wartość) usuwa pierwsze wystąpienie wartości; .pop(indeks) usuwa i zwraca element.
  • Sortowanie w miejscu: metoda .sort() porządkuje listę w miejscu; funkcja wbudowana sorted(lista) zwraca nową posortowaną kopię.
Modyfikacja w miejscu (in-place modification): wykonanie operacji na mutowalnym obiekcie bezpośrednio w zaalokowanym dla niego obszarze pamięci RAM bez tworzenia nowego obiektu, co optymalizuje zużycie zasobów systemowych.
# Lista startowa
nums = [3, 1, 4, 1, 5, 9, 2, 6]

# Dodawanie
nums.append(10)
nums.insert(0, 100)

# Usuwanie
nums.remove(1)
ostatni = nums.pop()
print(f"Usunięty: {ostatni}")

# Sortowanie
nums.sort()
print(f"Posortowane: {nums}")

posortowane = sorted(nums, reverse=True)
print(f"Odwrotnie: {posortowane}")

# List slicing (krojenie)
cyfry = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(cyfry[2:5])   # [2, 3, 4]
print(cyfry[:4])    # [0, 1, 2, 3]
print(cyfry[5:])    # [5, 6, 7, 8, 9]
print(cyfry[::2])   # [0, 2, 4, 6, 8] co drugi
16/60
Słowniki: asocjacyjne pary klucz-wartość
Slajd omawia strukturę słowników (dict), konstrukcję w klamrach {}, unikalność kluczy oraz operacje na parach klucz-wartość.

Tablice mieszające i szybki dostęp do danych

  • Konstrukcja słownika ({}): kolekcja par klucz: wartość, w której każdy klucz musi być obiektem niemutowalnym (hashable).
  • Błyskawiczny dostęp O(1): wyszukiwanie wartości po kluczu opiera się na tablicy mieszającej i odbywa się w czasie stałym.
  • Bezpieczny odczyt (.get()): metoda slownik.get(klucz, domyslna) zapobiega zgłoszeniu błędu KeyError, gdy klucz nie istnieje.
  • Iteracja po słowniku: metody .keys(), .values() oraz .items() zwracające dynamiczne widoki par do przetwarzania w pętlach.
Słownik w Pythonie (dict): wysoce zoptymalizowana implementacja tablicy mieszającej (hash map), przechowująca powiązania unikalnych kluczy z dowolnymi obiektami wartości, zachowująca kolejność wstawiania elementów od wersji Python 3.7.
# Tworzenie słownika
student = {
    "imie": "Anna",
    "nazwisko": "Kowalska",
    "wiek": 20,
    "kierunek": "Informatyka"
}

print(student)
print(student["imie"])

# Bezpieczny dostęp z domyślną wartością
telefon = student.get("telefon", "brak danych")
print(f"Telefon: {telefon}")

# Dodawanie/modyfikacja
student["telefon"] = "123-456-789"
student["wiek"] = 21
print(student)

# Iteracja po słowniku
for klucz in student:
    print(f"{klucz}: {student[klucz]}")

# Bardziej elegancko:
for klucz, wartosc in student.items():
    print(f"{klucz}: {wartosc}")

# Usuwanie
del student["telefon"]
print(student)
17/60
Instrukcje warunkowe: if, elif, else
Slajd wyjaśnia zasady rozgałęziania kodu za pomocą instrukcji if, elif, else oraz rygor stosowania 4 spacji wcięcia.

Sterowanie przepływem i wcięcia blokowe

  • Składnia blokowa z dwukropkiem: każda linia warunkowa kończy się dwukropkiem (:), a kod zależny musi być wcięty.
  • Standard wcięć PEP 8: oficjalnym standardem branżowym są 4 spacje na każdy poziom zagnieżdżenia; zakaz mieszania spacji i tabulatorów.
  • Gałęzie wielowariantowe (elif): krokowa weryfikacja kolejnych warunków wykluczających; wykonuje się wyłącznie pierwszy prawdziwy blok.
  • Wyrażenie trójargumentowe (ternary): zwięzły jednoliniowy zapis warunku: wartosc_gdy_prawda if warunek else wartosc_gdy_falsz.
Zasada wcięć blokowych (off-side rule): cecha syntaktyczna języka Python, w której struktura bloków programu (ciała warunków, pętli i funkcji) jest definiowana wyłącznie poziomem wcięć tekstu, a nie nawiasami klamrowymi czy słowami kluczowymi end.
# Prosty przykład
wiek = 18

if wiek >= 18:
    print("Jesteś pełnoletni!")
    print("Możesz głosować.")
else:
    print("Nie jesteś jeszcze pełnoletni.")

# else if (elif)
wynik = 75

if wynik >= 90:
    print("Ocena: bardzo dobry (5)")
elif wynik >= 70:
    print("Ocena: dobry (4)")
elif wynik >= 50:
    print("Ocena: dostateczny (3)")
else:
    print("Ocena: niedostateczny (2)")

# Warunek złożony (and, or)
login = "admin"
haslo = "12345"

if login == "admin" and haslo == "12345":
    print("Zalogowany!")
elif login == "admin":
    print("Złe hasło!")
else:
    print("Nieznany użytkownik.")
18/60
Pętla for: powtarzanie czynności
Slajd przedstawia pętlę for element in kolekcja, automatyczne pobieranie obiektów oraz generowanie sekwencji funkcją range().

Iteracja po kolekcjach i funkcja range()

  • Uniwersalny iterator: pętla for w Pythonie przechodzi bezpośrednio po elementach dowolnego obiektu iterowalnego (lista, string, plik).
  • Generator sekwencji range(): funkcja range(start, stop, krok) generuje ciągi liczb całkowitych w sposób leniwy (lazy evaluation).
  • Funkcja enumerate(): umożliwia jednoczesne pobieranie indeksu liczbowego oraz wartości elementu w pętli: for i, val in enumerate(kolekcja):.
  • Funkcja zip(): pozwala na równoległe iterowanie po dwóch lub więcej kolekcjach jednocześnie w parach krotek.
Iterator w Pythonie: obiekt implementujący protokół iteratora (__iter__() oraz __next__()), umożliwiający sekwencyjne pobieranie kolejnych elementów kolekcji bez konieczności ładowania całego zbioru do pamięci operacyjnej.
# Powtarzanie czynności
for i in range(5):
    print(f"Krok numer {i}")

# Iteracja po liście
owoce = ["jabłko", "banan", "wiśnia"]
for owoc in owoce:
    print(f"Lubię {owoc}")

# Enumerate - indeks i wartość
for index, owoc in enumerate(owoce):
    print(f"{index + 1}. {owoc}")

# range() z parametrami
print("Liczby parzyste od 0 do 10:")
for i in range(0, 11, 2):
    print(i, end=" ")

# break - wyjście z pętli
print("\nSzukam liczby 7:")
for i in range(10):
    if i == 7:
        print(f"Znalazłem! To liczba {i}")
        break
    print(f"Sprawdzam {i}...")

# continue - pomijanie iteracji
print("\nLiczby nieparzyste:")
for i in range(10):
    if i % 2 == 0:
        continue
    print(i, end=" ")
19/60
Pętla while: powtarzaj, dopóki warunek
Slajd omawia pętlę while warunek:, mechanizm powtarzania instrukcji do momentu zmiany warunku oraz unikanie pętli nieskończonych.

Pętle warunkowe i kontrola zakończenia

  • Zasada działania pętli while: blok instrukcji wykonuje się wielokrotnie tak długo, jak długo testowane wyrażenie zachowuje wartość True.
  • Modyfikacja stanu: ciało pętli musi modyfikować zmienne wchodzące w skład warunku (np. licznik += 1), aby pętla mogła się zakończyć.
  • Zastosowania: odczyt strumieni danych, oczekiwanie na zdarzenie sieciowe, menu konsolowe i interaktywne gry.
  • Pętla główna (while True): często stosowany wzorzec z jawnym przerwaniem instrukcją break wewnątrz ciała po spełnieniu warunku wyjścia.
Pętla warunkowa while: podstawowa struktura sterująca w Pythonie wykonująca kod, dopóki logiczne wyrażenie kontrolne ewaluuje się do prawdy, sprawdzana przed każdym wejściem do iteracji.
# Prosty licznik
licznik = 0
while licznik < 5:
    print(f"Wartość: {licznik}")
    licznik += 1  # UWAGA! Zawsze zwiększaj!

print("Koniec pętli")

# Wczytywanie, dopóki niepoprawne
haslo = ""
while haslo != "tajne":
    haslo = input("Podaj hasło: ")
    if haslo != "tajne":
        print("Złe hasło, spróbuj ponownie!")

print("Poprawne hasło! Zalogowany!")

# Symulacja odliczania
print("\nOdliczanie:")
i = 5
while i > 0:
    print(i)
    i -= 1
print("Start!")

# Pętla nieskończona (NIE RÓB TEGO!)
# while True:
#     print("Nieskończona pętla!")
# Aby przerwać: Ctrl + C
20/60
Sterowanie pętlami: break, continue, pass
Slajd przedstawia instrukcje sterujące przerwaniem pętli (break), przejściem do kolejnego kroku (continue) oraz instrukcję pustą (pass).

Modyfikacja naturalnego przepływu iteracji

  • Instrukcja break: natychmiast przerywa działanie bieżącej pętli for lub while i przenosi wykonanie za jej blok.
  • Instrukcja continue: przerywa wyłącznie bieżący krok iteracji i natychmiast przechodzi do sprawdzania kolejnego elementu.
  • Instrukcja pusta (pass): syntaktyczny wypełniacz (placeholder) nie wykonujący żadnej akcji, stosowany przy pustych blokach kodu.
  • Klauzula else w pętlach: unikalna cecha Pythona: blok else: po pętli wykonuje się TYLKO wtedy, gdy pętla zakończyła się naturalnie bez break.
Instrukcja break i continue: specjalne słowa kluczowe języka modyfikujące sekwencyjny cykl wykonania pętli: break dokonuje natychmiastowej ewakuacji z pętli, a continue pomija pozostałe instrukcje w bieżącej iteracji.
# BREAK - wyjście z pętli
print("Szukam pierwszej liczby większej od 100:")
for liczba in [10, 50, 90, 120, 150, 180]:
    if liczba > 100:
        print(f"Znalazłem: {liczba}")
        break
    print(f"Sprawdzam: {liczba}")

# CONTINUE - pomijanie elementów
print("\nWyświetlam tylko pliki (pomijam foldery):")
elementy = ["plik1.txt", "folder", "plik2.txt", "folder2", "plik3.txt"]
for element in elementy:
    if element.startswith("folder"):
        continue
    print(f"  - {element}")

# PASS - puste miejsce w kodzie
print("\nPrzykład z pass:")
for i in range(5):
    if i == 2:
        pass  # TODO: coś tu kiedyś będzie
    else:
        print(f"Przetwarzam element {i}")

# Praktyczny przykład: liczenie do napotkania błędu
print("\nPrzetwarzanie z limitem błędów:")
bledy = 0
for i in range(20):
    if bledy >= 3:
        print(f"Zbyt wiele błędów ({bledy}). Przerywam!")
        break
    print(f"Przetwarzanie {i}...")
    if i == 5 or i == 10:
        print(f"  Błąd przy {i}!")
        bledy += 1
21/60
Funkcje: wielokrotne użycie kodu
Slajd wyjaśnia zasady modularności, słowo kluczowe def, przekazywanie parametrów oraz czystość architektury kodu.

Definiowanie procedur słowem def

  • Deklaracja funkcji (def): składnia def nazwa_funkcji(parametry): tworzy nazwany, wielokrotnego użytku podprogram.
  • Zasada DRY (Don't Repeat Yourself): hermetyzacja powtarzalnych fragmentów kodu w funkcje ułatwia testowanie i eliminuje błędy.
  • Parametry a argumenty: parametry to nazwy zdefiniowane w nagłówku funkcji; argumenty to rzeczywiste wartości przekazane przy wywołaniu.
  • Wartości domyślne: możliwość zdefiniowania parametru domyślnego stosowanego wtedy, gdy argument nie zostanie podany.
Funkcja w Pythonie (function): obiekt pierwszej kategorii (first-class citizen) reprezentujący wywoływalny blok kodu źródłowego, który może przyjmować argumenty, zwracać wyniki, być przypisywany do zmiennych oraz przekazywany jako parametr.
# Definicja funkcji
def powitaj():
    """Funkcja wyświetlająca powitanie."""
    print("=" * 30)
    print("  Witaj w programie!")
    print("=" * 30)

# Wywołanie funkcji
powitaj()
powitaj()

# Funkcja z parametrem
def powitaj_osobe(imie):
    """Funkcja wita konkretną osobę."""
    print(f"Cześć, {imie}!")
    print("Miło Cię widzieć!")

powitaj_osobe("Anna")
powitaj_osobe("Bartek")

# Funkcja z wieloma parametrami
def dodaj(a, b):
    """Funkcja dodaje dwie liczby."""
    wynik = a + b
    print(f"{a} + {b} = {wynik}")

dodaj(5, 3)
dodaj(10, 20)

# Funkcja z parametrem domyślnym
def przywitaj(imie, czas_dnia="Dzień"):
    """Funkcja z pożegnaniem zależnym od pory dnia."""
    print(f"{czas_dnia}, {imie}!")

przywitaj("Anna")
przywitaj("Bartek", "Wieczór")
przywitaj("Celina", "Noc")
22/60
Funkcje: zwracanie wartości (return)
Slajd omawia instrukcję return, zwracanie danych do wywołującego oraz domyślną wartość None przy braku jawnego zwrotu.

Przekazywanie wyników obliczeń do programu

  • Instrukcja return: natychmiast kończy działanie funkcji i przekazuje wskazany obiekt do miejsca jej wywołania.
  • Zwracanie wielu wartości: zapis return a, b w rzeczywistości pakuje wyniki w niemutowalną krotkę (tuple), którą można rozpakować.
  • Domyślna wartość None: jeżeli funkcja nie posiada instrukcji return lub wykona sam return bez argumentu, automatycznie zwraca obiekt None.
  • Funkcje czyste (pure functions): dobre praktyki zalecają projektowanie funkcji, które zwracają wyniki zamiast polegać na skutkach ubocznych.
Wartość zwracana (return value): obiekt przekazywany z wnętrza funkcji do nadrzędnego kontekstu programu w momencie wykonania instrukcji return, stanowiący rezultat przetwarzania algorytmicznego.
# Funkcja zwracająca wartość
def dodaj(a, b):
    return a + b

def odejmij(a, b):
    return a - b

# Użycie wyniku
wynik = dodaj(10, 5)
print(f"Wynik dodawania: {wynik}")

# Łączenie funkcji
print(f"10 + 5 - 3 = {odejmij(dodaj(10, 5), 3)}")

# Funkcja zwracająca wiele wartości (krotka)
def dzielenie_z_reszta(a, b):
    calkowite = a // b
    reszta = a % b
    return calkowite, reszta

czesc, reszta = dzielenie_z_reszta(17, 5)
print(f"17 / 5 = {czesc} r. {reszta}")

# Funkcja bez return zwraca None
def brak_return():
    print("Coś robię, ale nic nie zwracam")

wynik = brak_return()
print(f"Wynik: {wynik}")

# Warunkowy return
def sprawdz_parzystosc(liczba):
    if liczba % 2 == 0:
        return True
    else:
        return False

print(f"4 parzyste? {sprawdz_parzystosc(4)}")
print(f"7 parzyste? {sprawdz_parzystosc(7)}")
23/60
Zasięg zmiennych: lokalny i globalny
Slajd wyjaśnia przestrzeń nazw w Pythonie, regułę rozwiązywania zasięgów LEGB oraz niebezpieczeństwa nadużywania zmiennych globalnych.

Reguła LEGB i słowo kluczowe global

  • Zmienne lokalne: zmienne zadeklarowane wewnątrz funkcji istnieją wyłącznie podczas jej wykonania na stosie wywołań.
  • Zmienne globalne: zmienne zdefiniowane na poziomie modułu; widoczne wewnątrz funkcji wyłącznie w trybie do odczytu.
  • Słowo kluczowe global: jawna deklaracja pozwalająca na modyfikację zmiennej z poziomu modułu wewnątrz funkcji (antywzorzec projektowy).
  • Hierarchia LEGB: kolejność poszukiwania zmiennych przez interpreter: Local -> Enclosing -> Global -> Built-in.
Reguła LEGB (scope resolution): formalny algorytm rozwiązywania nazw identyfikatorów w języku Python, przeszukujący kolejno zasięg lokalny funkcji (L), zasięg funkcji nadrzędnej (E), zasięg globalny modułu (G) oraz wbudowane symbole środowiska (B).
# Zmienna globalna
moja_liczba = 10

def funkcja_zmieniajaca():
    """Ta funkcja nie zmienia zmiennej globalnej!"""
    moja_liczba = 20  # To jest zmienna LOKALNA!
    print(f"Wewnątrz funkcji: {moja_liczba}")  # 20

funkcja_zmieniajaca()
print(f"Na zewnątrz: {moja_liczba}")  # 10 (bez zmiany!)

# Aby faktycznie zmienić globalną:
def funkcja_poprawna():
    global moja_liczba
    moja_liczba = 20
    print(f"Wewnątrz funkcji: {moja_liczba}")

funkcja_poprawna()
print(f"Na zewnątrz: {moja_liczba}")  # 20

# Lepszy sposób - parametry i return
def dodaj_cztery(x):
    return x + 4

wynik = dodaj_cztery(moja_liczba)
print(f"Wynik: {wynik}")
print(f"Globalna nadal: {moja_liczba}")
24/60
Elastyczne argumenty funkcji: *args i kwargs
Slajd przedstawia mechanizm pakowania i rozpakowywania argumentów pozycyjnych (*args) oraz nazwanych (kwargs).

Obsługa zmiennej liczby parametrów

  • Argumenty pozycyjne (*args): operator gwiazdki pakuje dowolną liczbę przekazanych argumentów pozycyjnych w krotkę (tuple).
  • Argumenty nazwane (kwargs): podwójna gwiazdka pakuje wszystkie nadmiarowe argumenty klucz=wartość w słownik (dict).
  • Kolejność w nagłówku: ścisły porządek parametrów: argumenty standardowe, wartości domyślne, *args, a na końcu kwargs.
  • Rozpakowywanie kolekcji: stosowanie * i przy wywołaniu funkcji do natychmiastowego rozbicia listy lub słownika na osobne argumenty.
Operatory *args i kwargs: składniowy mechanizm języka Python umożliwiający definiowanie funkcji o zmiennej liczbie argumentów (variadic functions), pozwalający na tworzenie uniwersalnych dekoratorów i funkcji opakowujących.
# *args - dowolna liczba argumentów pozycyjnych
def sumuj_wszystko(*liczby):
    """Sumuje dowolną liczbę liczb."""
    suma = 0
    for liczba in liczby:
        suma += liczba
    return suma

print(sumuj_wszystko(1, 2, 3))
print(sumuj_wszystko(10, 20, 30, 40))
print(sumuj_wszystko(5))

# kwargs - dowolna liczba argumentów nazwanych
def drukuj_dane(informacje):
    """Wyświetla dane osobowe."""
    for klucz, wartosc in informacje.items():
        print(f"{klucz}: {wartosc}")

drukuj_dane(imie="Anna", wiek=20, miasto="Warszawa")

# Połączenie *args i kwargs
def kompletna_funkcja(*args, kwargs):
    print(f"Argumenty pozycyjne: {args}")
    print(f"Argumenty nazwane: {kwargs}")

kompletna_funkcja(1, 2, 3, imie="Test", status="OK")

# Praktyczny przykład
def srednia(*oceny):
    if not oceny:
        return 0
    return sum(oceny) / len(oceny)

print(f"Średnia: {srednia(5, 4, 3, 5)}")
25/60
Obsługa plików: odczyt danych
Slajd omawia bezpieczny odczyt plików tekstowych za pomocą instrukcji with open(), tryb 'r' oraz kodowanie encoding='utf-8'.

Menedżer kontekstu with open() i odczyt z dysku

  • Menedżer kontekstu (with): konstrukcja with open(...) as f: gwarantuje natychmiastowe zamknięcie pliku nawet w razie awarii.
  • Metoda .read(): wczytuje całą zawartość pliku do pojedynczego łańcucha znaków typu str.
  • Metody .readline() i .readlines(): odczytują plik linijka po linijce lub zwracają kompletną listę wszystkich wierszy tekstu.
  • Iteracja bezpośrednia: najbardziej wydajny pamięciowo wzorzec: for linia in plik: przetwarza plik strumieniowo bez buforowania całości.
Menedżer kontekstu (context manager): obiekt zarządzający cyklem życia zasobów systemowych (plików, gniazd sieciowych, blokad) implementujący metody __enter__() oraz __exit__(), wywoływany składnią with w celu gwarantowanego zwolnienia zasobów.
# Odczyt całego pliku
with open("plik.txt", "r", encoding="utf-8") as plik:
    tresc = plik.read()
    print(tresc)

# Odczyt linia po linii
with open("plik.txt", "r", encoding="utf-8") as plik:
    for linia in plik:
        print(linia.strip())

# Odczyt wszystkich linii do listy
with open("plik.txt", "r", encoding="utf-8") as plik:
    linie = plik.readlines()
    for i, linia in enumerate(linie):
        print(f"{i+1}: {linia.strip()}")

# Bezpieczne otwieranie (starsza metoda)
try:
    plik = open("dane.txt", "r")
    dane = plik.read()
    print(dane)
finally:
    plik.close()

# Sprawdzanie czy plik istnieje
import os
if os.path.exists("plik.txt"):
    print("Plik istnieje!")
else:
    print("Plik nie istnieje.")
26/60
Obsługa plików: zapis danych
Slajd przedstawia techniki utrwalania danych na dysku: tryb nadpisywania 'w', dopisywanie na końcu 'a' oraz metody write() i writelines().

Tryby zapisu 'w' oraz dopisywania 'a'

  • Tryb zapisu ('w'): otwiera plik do zapisu; jeżeli plik już istniał, jego dotychczasowa zawartość zostaje bezpowrotnie skasowana.
  • Tryb dopisywania ('a'): dopisuje nowe dane na samym końcu pliku (append), zachowując wcześniejszą treść nienaruszoną.
  • Metoda .write(): zapisuje przekazany ciąg znaków; w przeciwieństwie do print() nie dodaje automatycznie znaku nowej linii \n.
  • Metoda .writelines(): przyjmuje listę ciągów tekstowych i sekwencyjnie zapisuje je wszystkie do otwartego pliku.
Operacja zapisu plikowego: proces przekazania bufora danych z pamięci operacyjnej do kontrolera systemu plików za pośrednictwem deskryptora wejścia/wyjścia, zakończony operacją zrzucenia bufora (flush).
# Zapis do nowego pliku (tryb "w")
with open("nowy_plik.txt", "w", encoding="utf-8") as plik:
    plik.write("Pierwsza linia\n")
    plik.write("Druga linia\n")
    plik.write("Trzecia linia\n")

print("Plik został zapisany!")

# Dopisywanie do istniejącego pliku (tryb "a")
with open("nowy_plik.txt", "a", encoding="utf-8") as plik:
    plik.write("Czwarta linia (dopisana)\n")
    plik.write("Piąta linia (dopisana)\n")

print("Dopisano do pliku!")

# Zapis listy linii
linie_do_zapisu = ["Linia 1\n", "Linia 2\n", "Linia 3\n"]
with open("lista.txt", "w", encoding="utf-8") as plik:
    plik.writelines(linie_do_zapisu)

# Praktyczny przykład: zapis danych użytkownika
imie = "Anna"
wiek = 20
miasto = "Warszawa"

with open("uzytkownik.txt", "w", encoding="utf-8") as plik:
    plik.write(f"Imię: {imie}\n")
    plik.write(f"Wiek: {wiek}\n")
    plik.write(f"Miasto: {miasto}\n")

print("Dane zapisane!")
27/60
Moduł os: zarządzanie plikami i katalogami
Slajd omawia moduł os, pobieranie katalogu roboczego os.getcwd(), tworzenie folderów os.makedirs() oraz usuwanie plików os.remove().

Tradycyjne operacje systemowe w Pythonie

  • Rola modułu os: zapewnia przenośny interfejs programistyczny do funkcji jądra systemu operacyjnego.
  • Katalog roboczy: funkcja os.getcwd() zwraca bieżącą ścieżkę roboczą; os.chdir(sciezka) zmienia aktywny folder.
  • Tworzenie folderów: funkcja os.makedirs(sciezka, exist_ok=True) tworzy całą hierarchię zagnieżdżonych katalogów.
  • Inspekcja zawartości: funkcja os.listdir(sciezka) zwraca listę nazw wszystkich plików i folderów znajdujących się w danej lokalizacji.
Moduł os biblioteki standardowej: wbudowany w Pythona moduł systemowy udostępniający niskopoziomowe funkcje API zależne od platformy, umożliwiający zarządzanie procesami, zmiennymi środowiskowymi oraz strukturą systemu plików.
import os

# Aktualny katalog roboczy
katalog = os.getcwd()
print(f"Aktualny katalog: {katalog}")

# Lista plików w katalogu
pliki = os.listdir(".")
print(f"Pliki: {pliki}")

# Sprawdzenie czy plik/katalog istnieje
if os.path.exists("plik.txt"):
    print("Plik istnieje!")
else:
    print("Plik nie istnieje")

# Tworzenie katalogu
if not os.path.exists("nowy_katalog"):
    os.mkdir("nowy_katalog")
    print("Katalog utworzony!")

# Zmiana nazwy pliku
if os.path.exists("stary.txt"):
    os.rename("stary.txt", "nowy.txt")
    print("Zmieniono nazwę!")

# Usuwanie pliku
if os.path.exists("do_usuniecia.txt"):
    os.remove("do_usuniecia.txt")
    print("Plik usunięty!")

# Ścieżki - łączenie
sciezka = os.path.join("katalog", "podkatalog", "plik.txt")
print(f"Pełna ścieżka: {sciezka}")
28/60
Moduł pathlib: nowoczesna praca ze ścieżkami
Slajd przedstawia klasę Path z modułu pathlib, intuicyjny operator dzielenia / oraz przewagę nad tradycyjnym os.path.

Obiektowe ścieżki plikowe w standardzie PEP 428

  • Obiektowa klasa Path: reprezentuje ścieżkę w systemie plików jako pełnoprawny obiekt z bogatym zestawem metod i właściwości.
  • Operator dzielenia (/): składnia sciezka / 'podkatalog' / 'plik.txt' łączy elementy niezależnie od separatora systemu (\ lub /).
  • Odczyt metadanych: właściwości .name (nazwa z rozszerzeniem), .stem (sama nazwa), .suffix (rozszerzenie) oraz .parent (folder macierzysty).
  • Wygodne metody plikowe: metody .exists(), .is_file(), .is_dir(), .read_text(), .write_text() eliminują konieczność używania open().
Moduł pathlib (PEP 428): nowoczesny standard reprezentacji ścieżek w systemie plików wprowadzony w Pythonie 3.4, zastępujący operacje na płaskich łańcuchach znaków semantycznymi obiektami ścieżek zoptymalizowanymi pod kątem wieloplatformowości.
from pathlib import Path

# Tworzenie obiektu Path
sciezka = Path(".")
print(sciezka)

# Łączenie ścieżek (elegancko!)
plik = Path("dokumenty") / "notatki" / "notatka.txt"
print(plik)

# Właściwości ścieżki
print(f"Katalog: {plik.parent}")
print(f"Nazwa: {plik.name}")
print(f"Rozszerzenie: {plik.suffix}")

# Sprawdzanie istnienia
if plik.exists():
    print(f"Plik istnieje: {plik}")
else:
    print("Plik nie istnieje")

# Tworzenie katalogu
katalog = Path("nowy_katalog")
katalog.mkdir(exist_ok=True)

# Tworzenie pliku
plik.write_text("Zawartość pliku", encoding="utf-8")

# Odczyt pliku
zawartosc = plik.read_text(encoding="utf-8")
print(zawartosc)

# Usuwanie
plik.unlink()
katalog.rmdir()

# Lista plików z filtrem
for p in Path(".").glob("*.txt"):
    print(f"Plik txt: {p}")
29/60
Obsługa błędów: try i except
Slajd omawia mechanizm obsługi wyjątków za pomocą bloków try i except oraz zapobieganie awaryjnemu zrzucaniu programu.

Przechwytywanie wyjątków i odporność aplikacji

  • Pojęcie wyjątku (Exception): obiekt sygnalizujący błąd wykonawczy (np. ZeroDivisionError, FileNotFoundError, ValueError).
  • Blok chroniony try: kod narażony na wystąpienie błędu umieszcza się w sekcji try: pod nadzorem interpretera.
  • Przechwytywanie w except: sekcja except NazwaWyjatku as e: wykonuje się tylko wtedy, gdy w bloku try wystąpi określony błąd.
  • Zakaz czystego except:: najlepsze praktyki surowo zabraniają stosowania samego except: bez wskazania typu błędu, gdyż maskuje to błędy składniowe.
Wyjątek w Pythonie (Exception): obiekt dziedziczący po klasie BaseException reprezentujący anomalię wykonawczą w programie, przerywający standardowy przepływ instrukcji i wymagający obsłużenia w strukturze try/except.
# Próba odczytu nieistniejącego pliku
try:
    with open("nie_istnieje.txt", "r") as plik:
        print(plik.read())
except FileNotFoundError:
    print("Błąd: Plik nie istnieje!")

# Obsługa wielu typów błędów
try:
    liczba = int(input("Podaj liczbę: "))
    wynik = 10 / liczba
    print(f"Wynik: {wynik}")
except ValueError:
    print("Błąd: To nie jest liczba!")
except ZeroDivisionError:
    print("Błąd: Nie można dzielić przez zero!")
except Exception as e:
    print(f"Nieoczekiwany błąd: {e}")

# Przechwytywanie błędu z zmienną
try:
    wynik = 10 / 0
except ZeroDivisionError as blad:
    print(f"Złapano błąd: {blad}")
    print(f"Typ błędu: {type(blad)}")

# Blok else - wykonuje się gdy nie ma błędu
try:
    x = int("123")
except ValueError:
    print("Błąd konwersji!")
else:
    print(f"Udało się! x = {x}")
30/60
Obsługa błędów: finally i raise
Slajd przedstawia sekcję finally, klauzulę else w obsłudze wyjątków oraz jawne zgłaszanie błędów poleceniem raise.

Gwarantowane czyszczenie zasobów i zgłaszanie błędów

  • Blok gwarantowany finally: kod w sekcji finally wykonuje się ZAWSZE, niezależnie od tego, czy wystąpił błąd, czy wykonano return.
  • Klauzula else w try: blok else: po sekcji except wykonuje się wyłącznie wtedy, gdy w bloku try NIE wystąpił żaden błąd.
  • Zgłaszanie błędów (raise): instrukcja raise ValueError('Niepoprawne dane') pozwala programiście na jawne wywołanie wyjątku.
  • Tworzenie własnych wyjątków: definiowanie specyficznych klas błędów biznesowych dziedziczących po klasie Exception.
Instrukcja raise: słowo kluczowe języka Python służące do jawnego wygenerowania instancji wyjątku w określonym punkcie programu, przerywającego bieżącą funkcję w celu zakomunikowania błędu walidacji lub naruszenia założeń algorytmu.
# finally - wykonuje się zawsze
print("Przykład z finally:")
try:
    plik = open("testowy.txt", "r")
    print(plik.read())
    x = 1 / 0
except FileNotFoundError:
    print("Plik nie istnieje!")
except ZeroDivisionError:
    print("Dzielenie przez zero!")
finally:
    print("To wykonuje się ZAWSZE!")
    if 'plik' in locals():
        plik.close()
    print("Zasoby zwolnione.")

# raise - rzucanie własnych błędów
def sprawdz_wiek(wiek):
    """Funkcja sprawdza czy wiek jest poprawny."""
    if wiek < 0:
        raise ValueError("Wiek nie może być ujemny!")
    if wiek > 150:
        raise ValueError("Wiek jest niemożliwie duży!")
    return True

try:
    sprawdz_wiek(-5)
except ValueError as e:
    print(f"Błąd walidacji: {e}")

# Łączenie raise i except
def podziel(a, b):
    if b == 0:
        raise ZeroDivisionError("Nie można dzielić przez zero!")
    return a / b

try:
    wynik = podziel(10, 0)
except ZeroDivisionError as e:
    print(f"Błąd: {e}")
31/60
Argumenty wiersza poleceń: sys.argv
Slajd omawia listę sys.argv z modułu sys, indeksowanie argumentów oraz budowę prostych skryptów konsolowych.

Pobieranie parametrów wywołania z konsoli

  • Lista sys.argv: wbudowana lista łańcuchów tekstowych zawierająca argumenty przekazane do skryptu w momencie wywołania.
  • Element zerowy (sys.argv[0]): zawsze zawiera nazwę lub ścieżkę uruchomionego pliku skryptu Python.
  • Kolejne parametry: wartości wpisane po nazwie skryptu trafiają kolejno do sys.argv[1], sys.argv[2] itd. jako typ str.
  • Ograniczenia sys.argv: brak wbudowanej walidacji, brak obsługi przełączników flagowych i konieczność ręcznego sprawdzania długości listy.
Lista sys.argv: obiekt listy w module sys udostępniający bezpośredni dostęp do argumentów wiersza poleceń przekazanych procesowi Pythona przez system operacyjny podczas jego uruchamiania.
# Zapisz jako: args_demo.py i uruchom:
# python args_demo.py plik.txt opcja1 opcja2

import sys

print(f"Nazwa skryptu: {sys.argv[0]}")
print(f"Liczba argumentów: {len(sys.argv)}")

# Wszystkie argumenty
print(f"Wszystkie argumenty: {sys.argv}")

# Iteracja po argumentach
for i, arg in enumerate(sys.argv):
    print(f"Argument {i}: {arg}")

# Bezpieczne pobieranie argumentów
if len(sys.argv) > 1:
    pierwszy_arg = sys.argv[1]
else:
    pierwszy_arg = "brak"

print(f"\nPierwszy argument: {pierwszy_arg}")

# Przykład praktyczny
# python args_demo.py copy plik_zrodlowy plik_docelowy
if len(sys.argv) >= 4:
    operacja = sys.argv[1]
    zrodlo = sys.argv[2]
    cel = sys.argv[3]
    print(f"{operacja}: {zrodlo} -> {cel}")
else:
    print("Użycie: python skrypt.py <operacja> <źródło> <cel>")
32/60
Krotki (tuples): niezmienne listy
Slajd przedstawia krotki (tuple), różnice wydajnościowe i semantyczne w stosunku do list oraz bezpieczeństwo danych niemutowalnych.

Niemutowalne sekwencje danych w nawiasach ()

  • Konstrukcja krotki (()): uporządkowana kolekcja elementów definiowana w nawiasach okrągłych: krotka = (1, 2, 'trzy').
  • Niemutowalność (immutability): elementów krotki nie można modyfikować, dodawać ani usuwać po jej utworzeniu.
  • Klucze w słownikach: dzięki niemutowalności krotka może być kluczem w słowniku dict lub elementem zbioru set (w przeciwieństwie do listy).
  • Wyższa wydajność: krotki zajmują mniej pamięci RAM i są szybciej alokowane przez interpreter niż listy o zmiennym rozmiarze.
Krotka w Pythonie (tuple): wbudowana, niemutowalna struktura sekwencyjna reprezentująca rekord danych o stałym rozmiarze, powszechnie stosowana do grupowania powiązanych wartości oraz zwracania wielu wyników z funkcji.
# Tworzenie krotek
wspolrzedne = (50.0, 19.9)  # szerokość, długość
kolor_rgb = (255, 128, 0)   # wartości RGB

# Dostęp do elementów
print(wspolrzedne[0])   # 50.0
print(wspolrzedne[1])   # 19.9
print(kolor_rgb[-1])    # 0

# Iteracja
for wartosc in kolor_rgb:
    print(wartosc)

# Rozpakowanie (unpacking)
x, y = wspolrzedne
print(f"X = {x}, Y = {y}")

# Konwersja lista <-> krotka
lista = [1, 2, 3]
krotka = tuple(lista)
nowa_lista = list(krotka)

# Krotka jednoelementowa (wymaga przecinka!)
jednoelementowa = (42,)  # WAŻNE: przecinek!
print(jednoelementowa)

# Funkcje zwracające krotki
def dzielenie(a, b):
    return a // b, a % b

wynik, reszta = dzielenie(17, 5)
print(f"17 / 5 = {wynik} r. {reszta}")
33/60
Zbiory (sets): unikalne elementy
Slajd omawia zbiory (set), eliminację powtórzeń, operacje mnogościowe oraz natychmiastowe sprawdzanie obecności O(1).

Matematyczna teoria mnogości i usuwanie duplikatów

  • Konstrukcja zbioru ({}): nieuporządkowana kolekcja unikalnych elementów definiowana w klamrach: zbior = {1, 2, 3} (pusty zbiór to set()).
  • Automatyczna eliminacja duplikatów: przekształcenie listy w zbiór: set(lista) natychmiast usuwa wszystkie powtarzające się wartości.
  • Błyskawiczne wyszukiwanie O(1): operacja x in zbior działa w czasie stałym dzięki wykorzystaniu funkcji skrótu.
  • Operacje na zbiorach: operatory sumy (|), iloczynu/przecięcia (&), różnicy (-) oraz różnicy symetrycznej (^).
Zbiór w Pythonie (set): mutowalna, nieuporządkowana kolekcja unikalnych i haszowalnych obiektów implementująca operacje algebry zbiorów, zoptymalizowana pod kątem testów przynależności o stałej złożoności obliczeniowej.
# Tworzenie zbioru
owoce = {"jabłko", "banan", "wiśnia", "jabłko"}
print(f"Owoce: {owoce}")  # jabłko tylko raz!

# Sprawdzanie przynależności
print("banan" in owoce)   # True
print("gruszka" in owoce) # False

# Dodawanie i usuwanie
owoce.add("gruszka")
print(f"Po dodaniu: {owoce}")
owoce.remove("banan")
print(f"Po usunięciu: {owoce}")
owoce.discard("winogrono")  # nie rzuca błędu

# Operacje na zbiorach
a = {1, 2, 3, 4, 5}
b = {4, 5, 6, 7, 8}

print(f"Suma: {a | b}")
print(f"Iloczyn: {a & b}")
print(f"Różnica a-b: {a - b}")
print(f"Różnica b-a: {b - a}")

# Usuwanie duplikatów z listy
lista = [1, 2, 3, 2, 1, 4, 3, 5]
unikalne = list(set(lista))
print(f"Bez duplikatów: {unikalne}")
34/60
List comprehensions: zwięzłe tworzenie list
Slajd wyjaśnia mechanizm list składanych (list comprehensions), ich składnię [wyrażenie for x in lista if warunek] oraz czytelność.

Eleganckie jednolinijkowe transformacje i filtrowanie

  • Składnia wyrażeń listowych: zwięzły zapis przekształcania i filtrowania danych wewnątrz nawiasów kwadratowych.
  • Zastępowanie pętli z append: konstrukcja [x*2 for x in dane if x > 0] zastępuje 4 linie tradycyjnej pętli for.
  • Wysoka wydajność wykonania: list comprehensions wykonują się szybciej niż zwykłe pętle dzięki optymalizacji na poziomie bajtkodu CPython.
  • Wyrażenia dla słowników i zbiorów: możliwość stosowania analogicznej składni dla słowników ({k: v for ...}) i zbiorów ({x for ...}).
Wyrażenie listowe (list comprehension): deklaratywna konstrukcja syntaktyczna w języku Python pozwalająca na tworzenie nowej listy poprzez zastosowanie wyrażenia transformującego oraz opcjonalnego filtru logicznego do każdego elementu sekwencji wejściowej.
# Tradycyjna pętla
kwadraty = []
for i in range(10):
    kwadraty.append(i ** 2)
print(f"Kwadraty: {kwadraty}")

# List comprehension - krótsza wersja
kwadraty = [i ** 2 for i in range(10)]
print(f"Kwadraty: {kwadraty}")

# Z warunkiem - tylko parzyste
parzyste = [i for i in range(20) if i % 2 == 0]
print(f"Parzyste: {parzyste}")

# Z transformacją - wielkie litery
imiona = ["anna", "bartek", "celina"]
wielkie = [imie.upper() for imie in imiona]
print(f"Wielkie: {wielkie}")

# Filtrowanie i transformacja
liczby = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
wynik = [x * 2 for x in liczby if x % 2 == 0]
print(f"Parzyste x2: {wynik}")

# Zagnieżdżone comprehension
macierz = [[i*j for j in range(3)] for i in range(3)]
print(f"Macierz 3x3: {macierz}")

# Wyciąganie rozszerzeń plików
pliki = ["dokument.docx", "obrazek.jpg", "tekst.txt", "foto.png"]
rozszerzenia = [p.split(".")[-1] for p in pliki]
print(f"Rozszerzenia: {set(rozszerzenia)}")
35/60
Moduł datetime: praca z datą i czasem
Slajd przedstawia moduł datetime, pobieranie bieżącego czasu, obliczenia na interwałach timedelta oraz formatowanie strftime.

Klasy date, datetime, timedelta oraz formatowanie

  • Bieżący czas (datetime.now()): zwraca pełny obiekt daty i czasu uwzględniający rok, miesiąc, dzień, godzinę, minuty i mikrosekundy.
  • Arytmetyka czasu (timedelta): dodawanie i odejmowanie przedziałów czasowych, np. datetime.now() - timedelta(days=7).
  • Formatowanie na tekst (strftime): konwersja obiektu daty na czytelny łańcuch tekstowy według formatu ISO lub regionalnego (np. '%Y-%m-%d %H:%M').
  • Parsowanie tekstu na datę (strptime): przekształcenie łańcucha znaków z pliku logu na obiekt daty umożliwiający porównywanie.
Moduł datetime: standardowy moduł Pythona dostarczający klasy do manipulacji datami i czasem, wspierający arytmetykę kalendarzową, porównania chronologiczne oraz konwersję stref czasowych.
import datetime

# Aktualna data i czas
teraz = datetime.datetime.now()
print(f"Teraz: {teraz}")

# Samo data
dzis = datetime.date.today()
print(f"Dziś: {dzis}")

# Formatowanie daty
print(teraz.strftime("%Y-%m-%d"))
print(teraz.strftime("%d.%m.%Y"))
print(teraz.strftime("%H:%M:%S"))
print(teraz.strftime("%Y-%m-%d %H:%M"))

# Tworzenie konkretnej daty
data_urodzin = datetime.date(2000, 5, 20)
print(f"Data urodzin: {data_urodzin}")

# Operacje na datach (timedelta)
jutro = teraz + datetime.timedelta(days=1)
tydzien_temu = teraz - datetime.timedelta(weeks=1)
za_godzinę = teraz + datetime.timedelta(hours=1)

print(f"Jutro: {jutro.strftime('%Y-%m-%d')}")

# Różnica między datami
d1 = datetime.date(2025, 1, 1)
d2 = datetime.date(2025, 1, 15)
roznica = d2 - d1
print(f"Różnica dni: {roznica.days}")

# Nazwa pliku z datą
def nazwa_pliku_z_data(prefix):
    data = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
    return f"{prefix}_{data}.txt"

print(nazwa_pliku_z_data("log"))
36/60
Formatowanie stringów: f-strings
Slajd omawia literały f-string (wprowadzone w Pythonie 3.6), bezpośrednie osadzanie wyrażeń w tekście oraz specyfikatory formatu.

Interpolacja zmiennych i wyrażeń w standardzie PEP 498

  • Prefiks f przed cudzysłowem: składnia f"Tekst: {zmienna}" nakazuje interpreterowi obliczenie wyrażeń w nawiasach klamrowych {}.
  • Dowolne wyrażenia wewnątrz {}: możliwość wywoływania funkcji i obliczeń w locie: f"Wynik: {2 + 2 * 10}" lub f"{nazwa.upper()}".
  • Specyfikatory formatowania: precyzyjna kontrola liczb dziesiętnych: {pi:.2f} (zaokrąglenie do 2 miejsc) lub wyrównanie kolumn {tekst:>20}.
  • Przewaga nad format() i %: f-strings są nieporównywalnie czytelniejsze i wykonują się zauważalnie szybciej niż starsze metody formatowania.
Formatowany łańcuch znaków (f-string / PEP 498): mechanizm interpolacji łańcuchów znaków w Pythonie ewaluowany w czasie wykonania, pozwalający na osadzanie dowolnych poprawnych wyrażeń języka wewnątrz literałów tekstowych.
# Podstawowe użycie
imie = "Anna"
wiek = 20
print(f"Nazywam się {imie} i mam {wiek} lat.")

# Wyrażenia w F-stringach
a = 10
b = 3
print(f"{a} + {b} = {a + b}")
print(f"{a} / {b} = {a / b:.2f}")

# Formatowanie liczb
cena = 1999.99
print(f"Cena: {cena:.2f} zł")
print(f"Cena: {cena:,.2f} zł")

# Procenty
procent = 0.256
print(f"Procent: {procent:.1%}")

# Wyrównywanie
imiona = ["Anna", "Bartek", "Celina"]
for i, imie in enumerate(imiona, 1):
    print(f"{i}. {imie:10} - OK")

# Data w F-stringu
import datetime
teraz = datetime.datetime.now()
print(f"Dzisiaj: {teraz:%Y-%m-%d}")

# Słowniki w F-stringach
student = {"imie": "Anna", "wiek": 20}
print(f"{student['imie']} ma {student['wiek']} lat")
37/60
Moduł json: dane w formacie JSON
Slajd przedstawia moduł json, funkcje dumps/loads (tekst) oraz dump/load (pliki) do wymiany danych w standardzie JSON.

Serializacja i deserializacja struktur danych

  • Rola formatu JSON: uniwersalny standard wymiany danych tekstowych w architekturze REST API i plikach konfiguracyjnych.
  • Serializacja (dumps i dump): przekształcenie struktur Pythona (słowników, list) na reprezentację tekstową formatu JSON.
  • Deserializacja (loads i load): wczytanie i sparsowanie tekstu JSON na natywne obiekty Pythona (dict, list, int, bool).
  • Opcje formatowania (indent): parametr indent=4 w json.dump() zapewnia czytelną dla człowieka strukturę wcięć (pretty-print).
Format JSON (JavaScript Object Notation): lekki, tekstowy format wymiany danych oparty na podzbiorze języka JavaScript, definiujący struktury par klucz-wartość oraz uporządkowanych list, natywnie odwzorowywany w Pythonie na słowniki i listy.
import json

# Python dict -> JSON string
dane = {
    "imie": "Anna",
    "wiek": 20,
    "kierunek": "Informatyka",
    "oceny": [5, 4, 3, 5]
}

json_string = json.dumps(dane, ensure_ascii=False, indent=2)
print("JSON string:")
print(json_string)

# JSON string -> Python dict
json_text = '{"imie": "Bartek", "wiek": 22}'
slownik = json.loads(json_text)
print(f"\nSłownik: {slownik}")
print(f"Imię: {slownik['imie']}")

# Zapisywanie do pliku JSON
with open("dane.json", "w", encoding="utf-8") as plik:
    json.dump(dane, plik, ensure_ascii=False, indent=4)

print("\nZapisano do pliku dane.json")

# Odczyt z pliku JSON
with open("dane.json", "r", encoding="utf-8") as plik:
    wczytane = json.load(plik)

print(f"Wczytane dane: {wczytane}")

# Sprawdzanie typu
print(f"\nTyp przed: {type(dane)}")
print(f"Typ JSON: {type(json_string)}")
38/60
Moduł subprocess: uruchamianie poleceń systemowych
Slajd omawia moduł subprocess, funkcję subprocess.run(), przechwytywanie wyjścia oraz reguły bezpieczeństwa związane z flagą shell=False.

Integracja z powłoką systemu operacyjnego

  • Funkcja subprocess.run(): rekomendowane, nowoczesne narzędzie do synchronicznego uruchamiania programów zewnętrznych w systemie.
  • Bezpieczeństwo (shell=False): przekazywanie polecenia jako listy argumentów ['ping', '-c', '4', host] zapobiega wstrzykiwaniu komend.
  • Przechwytywanie wyjścia (capture_output): parametry capture_output=True oraz text=True kierują wyniki polecenia do obiektu CompletedProcess.
  • Weryfikacja kodów wyjścia (check=True): automatyczne zgłoszenie wyjątku CalledProcessError w przypadku zakończenia programu kodem błędu.
Moduł subprocess: standardowy podsystem Pythona do tworzenia nowych procesów potomnych, podłączania ich potoków wejścia/wyjścia (stdin/stdout/stderr) oraz pobierania kodów powrotu z jądra systemu operacyjnego.
import subprocess
import sys

# Uruchomienie prostego polecenia
# W systemie Windows polecenie echo jest wbudowane w powłoce (cmd.exe),
# dlatego używamy shell=True - jest to wymagane dla wbudowanych poleceń Windows.
print("=== Pierwsze polecenie ===")
if sys.platform.startswith("win"):
    subprocess.run(["echo", "Witaj z Pythona!"], shell=True)
else:
    subprocess.run(["echo", "Witaj z Pythona!"])

# Pobranie wyniku polecenia
print("\n=== Z wynikiem ===")
if sys.platform.startswith("win"):
    wynik = subprocess.run(["echo", "Test Python"], capture_output=True, text=True, shell=True)
else:
    wynik = subprocess.run(["echo", "Test Python"], capture_output=True, text=True)
print(f"Wynik: {wynik.stdout}")

# Sprawdzenie kodu powrotu
print("\n=== Sprawdzenie kodu ===")
if sys.platform.startswith("win"):
    wynik = subprocess.run(["echo", "OK"], capture_output=True, text=True, shell=True)
else:
    wynik = subprocess.run(["echo", "OK"], capture_output=True, text=True)
print(f"Kod powrotu: {wynik.returncode}")  # 0 = sukces

# Obsługa błędów
print("\n=== Obsługa błędów ===")
try:
    if sys.platform.startswith("win"):
        subprocess.run(["nonexistent_command"], check=True, capture_output=True, text=True, shell=True)
    else:
        subprocess.run(["nonexistent_command"], check=True, capture_output=True, text=True)
except subprocess.CalledProcessError as e:
    print(f"Błąd polecenia: {e}")
except FileNotFoundError:
    print("Polecenie nie znalezione!")

# WAŻNE: Bezpieczne vs niebezpieczne
# Bezpiecznie (lista argumentów, shell=False):
# subprocess.run(["ping", "-n", "1", "8.8.8.8"])  # Windows
# subprocess.run(["ping", "-c", "1", "8.8.8.8"])  # Linux

# Niebezpiecznie (string ze shell=True - unikaj!):
# subprocess.run("ping -n 1 8.8.8.8", shell=True)
39/60
Moduł random: liczby losowe i losowy wybór
Slajd przedstawia moduł random, algorytm Mersenne Twister, funkcje randint(), choice(), sample() oraz shuffle().

Generowanie liczb pseudolosowych i tasowanie danych

  • Losowanie liczb całkowitych (randint): funkcja random.randint(a, b) generuje losową liczbę całkowitą z obustronnie domkniętego przedziału.
  • Losowy wybór elementu (choice): funkcja random.choice(lista) wybiera pojedynczy losowy element z przekazanej kolekcji.
  • Próbkowanie bez powtórzeń (sample): funkcja random.sample(kolekcja, k) pobiera unikalny podzbiór k elementów ze zbioru.
  • Tasowanie w miejscu (shuffle): funkcja random.shuffle(lista) losowo miesza kolejność elementów listy w pamięci operacyjnej.
Moduł random: moduł biblioteki standardowej implementujący generator liczb pseudolosowych oparty na algorytmie Mersenne Twister o okresie 2^19937-1, przeznaczony do symulacji i modelowania (niewskazany do kryptografii).
import random

# Losowa liczba całkowita
print("=== Losowe liczby ===")
for i in range(5):
    liczba = random.randint(1, 10)
    print(f"Losowa liczba 1-10: {liczba}")

# Liczba zmiennoprzecinkowa 0-1
print(f"\nFloat 0-1: {random.random():.4f}")

# Losowy wybór z listy
print("\n=== Losowy wybór ===")
owoce = ["jabłko", "banan", "wiśnia", "gruszka"]
print(f"Wylosowany owoc: {random.choice(owoce)}")

# Losowe hasło
znaki = "abcdefghijklmnopqrstuvwxyz0123456789"
haslo = "".join(random.choice(znaki) for _ in range(8))
print(f"Wygenerowane hasło: {haslo}")

# Przetasowanie listy
print("\n=== Przetasowanie ===")
karty = ["As", "Król", "Dama", "Walet", "10"]
print(f"Przed: {karty}")
random.shuffle(karty)
print(f"Po: {karty}")

# Losowa próbka (bez powtórzeń)
print("\n=== Losowa próbka ===")
liczby = list(range(1, 50))
wylosowane = random.sample(liczby, 6)
print(f"Wylosowane 6 z 49: {sorted(wylosowane)}")

# Symulacja rzutu kostką
print("\n=== Symulacja rzutu kostką ===")
for _ in range(5):
    wynik = random.randint(1, 6)
    print(f"Kostka: {wynik}")
40/60
Moduł re: wyrażenia regularne (regex)
Slajd omawia moduł re, podstawowe metaznaki wyrażeń regularnych oraz funkcje re.search(), re.findall() i re.sub().

Dopasowywanie wzorców i przetwarzanie tekstu

  • Rola wyrażeń regularnych: niezastąpione narzędzie do zaawansowanego przeszukiwania, walidacji i zamiany tekstu w plikach i logach.
  • Funkcja re.search(): przeszukuje cały ciąg i zwraca obiekt dopasowania Match dla pierwszego odnalezionego fragmentu.
  • Funkcja re.findall(): odnajduje wszystkie wystąpienia wzorca w tekście i zwraca je w postaci zwartej listy ciągów znaków.
  • Surowe łańcuchy znaków (r'...'): bezwzględny wymóg poprzedzania wzorców literą r, aby ukośniki odwrotne nie były traktowane jako znaki ucieczki Pythona.
Wyrażenia regularne (Regular Expressions / Regex): sformalizowany język wzorców tekstowych wykorzystujący metaznaki do opisu zbiorów łańcuchów znaków, implementowany w module re silnikiem dopasowywania z mechanizmem powrotów (backtracking).
import re

# Wzorzec na numer telefonu (uproszczony)
wzor = r"\d{3}-\d{3}-\d{3}"
tekst = "Mój numer: 123-456-789"
dopasowanie = re.search(wzor, tekst)
if dopasowanie:
    print(f"Znaleziono: {dopasowanie.group()}")

# Wyszukiwanie adresu e-mail
wzor_email = r"\w+@\w+\.\w+"
emails = "Napisz: jan@test.com lub anna@domena.pl"
znalezione = re.findall(wzor_email, emails)
print(f"E-maile: {znalezione}")

# Walidacja numeru telefonu
def sprawdz_telefon(numer):
    wzor = r"^\d{3}-\d{3}-\d{3}$"
    if re.match(wzor, numer):
        return True
    return False

print(f"123-456-789: {sprawdz_telefon('123-456-789')}")
print(f"12-34: {sprawdz_telefon('12-34')}")

# Zamiana tekstu
tekst = "Kolor: czerwony, smak: kwaśny"
nowy = re.sub(r"\w+", "XXX", tekst)
print(f"Zamienione: {nowy}")

# Wyciąganie liczb z tekstu
tekst = "Mam 5 jabłek i 10 pomarańczy"
liczby = re.findall(r"\d+", tekst)
print(f"Liczby: {[int(x) for x in liczby]}")
41/60
Zmienne środowiskowe: os.environ
Slajd przedstawia odczyt i modyfikację zmiennych środowiskowych przez słownik os.environ oraz zabezpieczanie kluczy API i haseł.

Konfiguracja aplikacji i bezpieczeństwo poświadczeń

  • Słownik os.environ: obiekt mapujący zmienne środowiskowe systemu operacyjnego na pary klucz-wartość w pamięci Pythona.
  • Bezpieczny odczyt (os.getenv()): funkcja os.getenv('NAZWA', domyslna) zapobiega awarii programu, gdy zmienna nie została zdefiniowana.
  • Zasada 12 Factor App: przechowywanie konfiguracji (haseł do baz danych, tokenów API) w zmiennych środowiskowych, nigdy w kodzie źródłowym.
  • Tymczasowa modyfikacja: przypisanie os.environ['ZMIENNA'] = wartosc działa wyłącznie w pamięci bieżącego procesu Pythona.
Zmienne środowiskowe procesu (os.environ): mechanizm przekazywania parametrów konfiguracyjnych i poświadczeń bezpieczeństwa z powłoki systemu operacyjnego do uruchamianego programu bez konieczności zapisywania ich w plikach kodu źródłowego.
import os

# Wszystkie zmienne środowiskowe (słownik)
print("=== Zmienne środowiskowe ===")
for klucz, wartosc in list(os.environ.items())[:5]:
    print(f"{klucz}: {wartosc}")

# Pobranie konkretnej zmiennej
print("\n=== Pobieranie zmiennych ===")
uzytkownik = os.environ.get("USERNAME") or os.environ.get("USER")
print(f"Nazwa użytkownika: {uzytkownik}")

katalog_domowy = os.environ.get("HOME") or os.environ.get("USERPROFILE")
print(f"Katalog domowy: {katalog_domowy}")

# System operacyjny
system = os.environ.get("OS") or os.name
print(f"System: {system}")

# Własna zmienna środowiskowa
# W terminalu: export MOJA_ZMIENNA=wartość
moja_zmienna = os.environ.get("MOJA_ZMIENNA", "domyślna")
print(f"Moja zmienna: {moja_zmienna}")

# Ustawianie zmiennej (tylko dla tego procesu)
os.environ["TEST"] = "wartość_testowa"
print(f"TEST: {os.environ.get('TEST')}")

# Ścieżka do pliku tymczasowego
temp_dir = os.environ.get("TEMP") or os.environ.get("TMP") or "/tmp"
print(f"Katalog tymczasowy: {temp_dir}")
42/60
Wykrywanie systemu operacyjnego: moduł sys i platform
Slajd omawia identyfikację platformy sprzętowej i programowej za pomocą sys.platform oraz modułu platform.

Pisanie skryptów w pełni przenośnych

  • Identyfikator sys.platform: zwraca krótki ciąg tekstowy identyfikujący platformę: 'win32' (Windows), 'linux' (Linux), 'darwin' (macOS).
  • Zaawansowane dane w module platform: funkcje platform.system(), platform.release(), platform.architecture() dostarczają szczegółów jądra.
  • Wieloplatformowe gałęzie kodu: konstrukcja if sys.platform == 'win32': pozwala na dostosowanie poleceń do konkretnego systemu.
  • Standaryzacja ścieżek: unikanie wpisywania separatorów ścieżek na sztywno dzięki stosowaniu modułu pathlib.
Wieloplatformowość kodu (cross-platform code): zasada projektowania oprogramowania w sposób uniwersalny, gwarantujący identyczne i bezbłędne wykonanie skryptu na systemach operacyjnych z rodziny Windows, Linux oraz macOS bez konieczności modyfikacji kodu.
import sys
import os

print("=== Informacje o systemie ===")
print(f"sys.platform: {sys.platform}")
print(f"os.name: {os.name}")

# Wykrywanie Windows
if sys.platform.startswith("win"):
    print("\nWykryto: Windows")
    print("Używam poleceń Windows: dir, type, copy")
    
# Wykrywanie Linux
elif sys.platform.startswith("linux"):
    print("\nWykryto: Linux")
    print("Używam poleceń Linux: ls, cat, cp")

# Wykrywanie macOS
elif sys.platform == "darwin":
    print("\nWykryto: macOS")
    print("Używam poleceń macOS")

# Ścieżki zależne od systemu
print("\n=== Ścieżki systemowe ===")
if sys.platform.startswith("win"):
    sciezka_konfig = os.path.join(os.environ["APPDATA"], "moja_app")
else:
    sciezka_konfig = os.path.join(os.environ["HOME"], ".moja_app")
    
print(f"Ścieżka konfiguracji: {sciezka_konfig}")

# Komendy zależne od systemu
def wyczysc_ekran():
    if sys.platform.startswith("win"):
        os.system("cls")
    else:
        os.system("clear")

print("\nGotowe do wyczyszczenia ekranu.")
43/60
Moduł shutil: zaawansowane operacje na plikach
Slajd przedstawia moduł shutil, funkcje kopiowania shutil.copy2(), rekursywne usuwanie shutil.rmtree() oraz pakowanie archiwów.

Kopiowanie, przenoszenie i rekursywne usuwanie folderów

  • Kopiowanie z metadanymi (shutil.copy2): kopiuje zawartość pliku wraz ze wszystkimi atrybutami, czasem modyfikacji i uprawnieniami.
  • Kopiowanie całych drzew (shutil.copytree): rekursywnie kopiuje kompletny katalog wraz ze wszystkimi podfolderami i plikami.
  • Bezwarunkowe usuwanie (shutil.rmtree): usuwa wskazany folder bez względu na liczbę zawartych w nim plików i podkatalogów.
  • Tworzenie archiwów (make_archive): funkcja shutil.make_archive('kopia', 'zip', folder) automatycznie pakuje katalog do archiwum ZIP lub TAR.
Moduł shutil (shell utilities): wysokopoziomowy moduł biblioteki standardowej Pythona dedykowany do masowych operacji na plikach i drzewach katalogów, takich jak replikacja, archiwizacja oraz destrukcja struktur dyskowych.
import shutil
import os
from pathlib import Path

# Tworzenie struktury katalogów do testów
test_dir = Path("test_shutil")
test_dir.mkdir(exist_ok=True)
(test_dir / "plik.txt").write_text("Testowa zawartość")

# Kopiowanie pliku
print("=== Kopiowanie ===")
shutil.copy(test_dir / "plik.txt", test_dir / "kopia.txt")
print("Skopiowano plik.txt -> kopia.txt")

# Kopiowanie katalogu
print("\n=== Kopiowanie katalogu ===")
os.makedirs(test_dir / "folder", exist_ok=True)
shutil.copytree(test_dir, test_dir.parent / "kopia_folderu")
print(f"Skopiowano {test_dir} -> kopia_folderu")

# Przenoszenie/zmiana nazwy
print("\n=== Przenoszenie ===")
shutil.move(test_dir / "kopia.txt", test_dir / "przeniesiony.txt")
print("Przeniesiono kopia.txt -> przeniesiony.txt")

# Informacje o dysku
print("\n=== Informacje o dysku ===")
usage = shutil.disk_usage("/")
print(f"Całkowite: {usage.total / (10243):.2f} GB")
print(f"Używane: {usage.used / (10243):.2f} GB")
print(f"Wolne: {usage.free / (10243):.2f} GB")

# Sprzątanie
print("\n=== Sprzątanie ===")
shutil.rmtree(test_dir)
print("Usunięto test_shutil")
44/60
Moduł argparse: zaawansowane przetwarzanie argumentów
Slajd omawia klasę ArgumentParser z modułu argparse, definiowanie parametrów opcjonalnych, pozycyjnych oraz automatyczną pomoc --help.

Budowa pełnoprawnego interfejsu wiersza poleceń (CLI)

  • Klasa ArgumentParser: silnik parsowania argumentów wiersza poleceń z automatyczną walidacją i obsługą błędów.
  • Definiowanie argumentów (.add_argument): określanie flag (-v, --verbose), argumentów pozycyjnych, typów danych (type=int) i pomocy (help=...).
  • Automatyczny system pomocy: skrypt uruchomiony z parametrem --help lub -h automatycznie wyświetla estetycznie sformatowaną instrukcję obsługi.
  • Wbudowane sprawdzanie poprawności: argparse sam informuje użytkownika o brakujących argumentach lub niepoprawnych typach danych.
Moduł argparse: standardowy moduł Pythona do budowania interfejsów wiersza poleceń (CLI), automatyzujący proces parsowania opcji programu, weryfikacji typów oraz generowania dokumentacji konsolowej.
import argparse

# Tworzenie parsera
parser = argparse.ArgumentParser(
    description="Program do kalkulacji podatku VAT",
    epilog="Przykład: python vat.py --kwota 100 --stawka 23"
)

# Dodawanie argumentów
parser.add_argument("kwota", type=float, help="Kwota netto")
parser.add_argument("-s", "--stawka", type=float, default=23, 
                    help="Stawka VAT (domyślnie 23)")
parser.add_argument("-v", "--verbose", action="store_true",
                    help="Tryb szczegółowy")

# Parsowanie argumentów
args = parser.parse_args()

# Użycie argumentów
print(f"Kwota netto: {args.kwota}")
print(f"Stawka VAT: {args.stawka}%")

if args.verbose:
    print(f"Kwota brutto: {args.kwota * (1 + args.stawka/100):.2f}")
else:
    print(f"Wynik: {args.kwota * (1 + args.stawka/100):.2f}")

# === PRZYKŁADOWE URUCHOMIENIE ===
45/60
Moduł logging: rejestrowanie zdarzeń
Slajd przedstawia moduł logging, 5 standardowych poziomów istotności, konfigurację basicConfig oraz zapis do plików dziennika.

Architektura logowania zamiast polecenia print()

  • Dlaczego logging zamiast print?: umożliwia centralne sterowanie poziomem szczegółowości bez konieczności modyfikacji kodu aplikacji.
  • 5 poziomów istotności: DEBUG (diagnostyka), INFO (potwierdzenia), WARNING (ostrzeżenia), ERROR (błędy), CRITICAL (awarie krytyczne).
  • Konfiguracja logging.basicConfig(): określenie nazwy pliku docelowego (filename), formatu wpisu ze stemplem czasu oraz minimalnego poziomu.
  • Jednoczesne logowanie: możliwość równoległego zapisu zdarzeń do pliku dyskowego oraz wyświetlania komunikatów na ekranie konsoli.
Podsystem logowania (logging subsystem): moduł biblioteki standardowej Pythona implementujący wielopoziomowe rejestrowanie zdarzeń operacyjnych i błędów z obsługą formatowania znaczników czasu, rotacji plików oraz integracji z serwerami Syslog.
import logging

# Podstawowa konfiguracja
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s [%(levelname)s] %(message)s',
    datefmt='%H:%M:%S'
)

logger = logging.getLogger(__name__)

# Różne poziomy logowania
logger.debug("Informacja debug - szczegóły")
logger.info("Informacja ogólna - np. start programu")
logger.warning("Ostrzeżenie - coś może być nie tak")
logger.error("Błąd - coś poszło nie tak")
logger.critical("Błąd krytyczny - program nie może kontynuować")

# Przykład praktyczny
def funkcja_pobierajaca_dane(id):
    logger.info(f"Rozpoczynam pobieranie danych dla ID: {id}")
    
    try:
        logger.debug(f"Łączenie z bazą danych...")
        logger.debug(f"Zapytanie wykonane")
        logger.info(f"Pobieranie zakończone sukcesem")
        return {"id": id, "dane": "przykładowe"}
        
    except Exception as e:
        logger.error(f"Błąd pobierania danych: {e}")
        return None
46/60
Moduł urllib i komunikacja sieciowa
Slajd omawia urllib.request, pobieranie danych ze stron internetowych przez HTTP GET oraz alternatywną bibliotekę requests.

Wysyłanie zapytań HTTP i pobieranie danych z sieci

  • Funkcja urllib.request.urlopen(): wbudowane narzędzie do nawiązywania połączeń sieciowych i pobierania zawartości stron WWW.
  • Menedżer kontekstu z połączeniem: bezpieczne zamykanie gniazda sieciowego za pomocą składni with urllib.request.urlopen(url) as odp:.
  • Dekodowanie odpowiedzi: odczytane bajty odpowiedzi należy zdekodować do tekstu metodą .decode('utf-8').
  • Biblioteka requests: omówienie de facto standardu branżowego requests (instalowanego przez pip) jako bardziej ergonomicznej alternatywy.
Protokół HTTP (Hypertext Transfer Protocol): podstawowy protokół bezstanowy warstwy aplikacji w architekturze klient-serwer, służący do przesyłania dokumentów hipertekstowych oraz wymiany danych w internetowych usługach REST API.
import urllib.request
import json

# Pobieranie prostej strony
print("=== Pobieranie strony ===")
url = "https://jsonplaceholder.typicode.com/todos/1"

try:
    with urllib.request.urlopen(url, timeout=10) as response:
        dane = response.read().decode('utf-8')
        print(f"Odpowiedź: {dane}")
        
        # Parsowanie JSON
        dane_json = json.loads(dane)
        print(f"\nTitle: {dane_json['title']}")
        print(f"Completed: {dane_json['completed']}")
        
except Exception as e:
    print(f"Błąd: {e}")

# Sprawdzanie czy strona istnieje
print("\n=== Sprawdzanie URL ===")
def sprawdz_url(adres_url):
    try:
        with urllib.request.urlopen(adres_url, timeout=5) as response:
            return f"OK - kod {response.status}"
    except urllib.error.HTTPError as e:
        return f"HTTP Error: {e.code}"
    except urllib.error.URLError as e:
        return f"URL Error: {e.reason}"
    except Exception as e:
        return f"Błąd: {e}"

print(sprawdz_url("https://google.com"))
print(sprawdz_url("https://httpbin.org/status/404"))
47/60
Tworzenie własnych modułów
Slajd wyjaśnia zasady podziału programu na moduły wielokrotnego użytku, organizację importów oraz strażnika punktu wejścia.

Struktura plików, instrukcja import oraz if __name__ == '__main__'

  • Moduł jako plik .py: każdy plik z kodem Pythona może być zaimportowany do innego programu za pomocą instrukcji import nazwa.
  • Importowanie selektywne: składnia from moj_modul import funkcja_a, funkcja_b importuje wyłącznie wybrane komponenty.
  • Strażnik punktu wejścia: warunek if __name__ == '__main__': wykonuje kod testowy tylko wtedy, gdy plik uruchomiono bezpośrednio.
  • Katalog pamięci podręcznej (__pycache__): automatyczne generowanie skompilowanego bajtkodu .pyc przyspieszającego kolejne importy.
Punkt wejścia programu (__name__ == '__main__'): idiomatyczny wzorzec projektowy w języku Python rozróżniający bezpośrednie uruchomienie pliku skryptu od zaimportowania go jako biblioteki pomocniczej przez inny moduł.
# === PLIK: moje_narzedzia.py ===

STALA_PI = 3.14159
WERSJA = "1.0"

def powitaj(imie):
    """Funkcja wita użytkownika."""
    return f"Cześć, {imie}!"

def oblicz_pole_kola(promien):
    """Oblicza pole koła."""
    return STALA_PI * promien ** 2

# === PLIK: main.py ===

import moje_narzedzia

# Użycie funkcji z modułu
print(moje_narzedzia.powitaj("Anna"))
print(f"Wersja: {moje_narzedzia.WERSJA}")

# Import z aliasem
import moje_narzedzia as mn
print(mn.oblicz_pole_kola(5))

# Import konkretnych elementów
from moje_narzedzia import powitaj, oblicz_pole_kola
print(powitaj("Bartek"))
print(oblicz_pole_kola(10))
48/60
Moduł sys: parametry środowiska uruchomieniowego
Slajd omawia moduł sys, sterowanie zakończeniem programu sys.exit(), ścieżki przeszukiwania sys.path oraz rozmiar obiektów sys.getsizeof().

Inspekcja interpretera i zarządzanie procesem

  • Zakończenie programu (sys.exit): natychmiastowe przerwanie programu z jawnym kodem wyjścia zwracanym do systemu operacyjnego (np. sys.exit(0)).
  • Ścieżka importów (sys.path): lista katalogów, w których interpreter poszukuje importowanych modułów i pakietów bibliotecznych.
  • Rozmiar obiektów w pamięci: funkcja sys.getsizeof(obiekt) zwraca fizyczną liczbę bajtów pamięci RAM alokowaną przez dany obiekt.
  • Strumienie wejścia/wyjścia: bezpośredni dostęp do niskopoziomowych strumieni sys.stdin, sys.stdout oraz sys.stderr.
Moduł sys biblioteki standardowej: wbudowany moduł Pythona udostępniający zmienne i funkcje silnie powiązane z samym interpreterem CPython oraz jego interakcją z systemem operacyjnym hosta.
import sys

print("=== Informacje o Pythonie ===")
print(f"Wersja Pythona: {sys.version}")
print(f"Wersja (krótka): {sys.version_info}")
print(f"Wersja główna: {sys.version_info.major}.{sys.version_info.minor}")

print(f"\nŚcieżka do Pythona: {sys.executable}")

print(f"\nPlatforma: {sys.platform}")

print("\n=== Ścieżki wyszukiwania modułów ===")
for i, sciezka in enumerate(sys.path[:5]):
    print(f"{i+1}. {sciezka}")

# Zakończenie programu
# sys.exit(0)  # 0 = normalne zakończenie
# sys.exit(1)  # 1 = błąd

# Przekierowanie wyjścia
print("\n=== Standardowe wyjście ===")
print(f"Obiekt stdout: {sys.stdout}")

# Sprawdzanie wersji
if sys.version_info.major >= 3:
    print("\nUżywasz Python 3!")
    if sys.version_info.minor >= 8:
        print("Masz przynajmniej Python 3.8")
49/60
Moduł collections: zaawansowane struktury danych
Slajd przedstawia rozszerzone struktury danych z modułu collections: zliczanie elementów (Counter), słowniki z wartością domyślną oraz nazwane krotki.

Kolekcje Counter, defaultdict oraz namedtuple

  • Klasa Counter: wyspecjalizowany słownik do błyskawicznego zliczania częstotliwości wystąpień elementów w dowolnej kolekcji.
  • Klasa defaultdict: słownik automatycznie tworzący wartość domyślną przy próbie odwołania do nieistniejącego klucza.
  • Nazwane krotki (namedtuple): krotki umożliwiające dostęp do pól zarówno przez indeksy, jak i czytelne nazwy atrybutów.
  • Kolejka dwustronna (deque): kolekcja o błyskawicznym dodawaniu i usuwaniu elementów z obu końców o złożoności O(1).
Moduł collections: moduł Pythona implementujący zaawansowane, wysoce zoptymalizowane struktury danych stanowiące alternatywę dla wbudowanych typów ogólnych list, dict i tuple.
from collections import Counter, defaultdict, namedtuple, deque

# === Counter - zliczanie elementów ===
print("=== Counter ===")
owoce = ["jabłko", "banan", "jabłko", "wiśnia", "banan", "jabłko"]
zlicz = Counter(owoce)
print(f"Zliczone: {zlicz}")
print(f"Najczęstsze: {zlicz.most_common(2)}")

# Zliczanie słów w tekście
tekst = "to jest tekst z kilkoma słowami i tekst i jeszcze więcej słów"
slowa = tekst.split()
zlicz_slow = Counter(slowa)
print(f"Słowa: {zlicz_slow.most_common(3)}")

# === defaultdict - słownik z domyślną wartością ===
print("\n=== defaultdict ===")
dd = defaultdict(int)  # domyślna wartość to 0
dd["jabłka"] += 1
dd["banany"] += 5
print(f"dd: {dict(dd)}")

# === namedtuple - krotka z nazwami pól ===
print("\n=== namedtuple ===")
Osoba = namedtuple("Osoba", ["imie", "wiek", "miasto"])
anna = Osoba("Anna", 20, "Warszawa")
print(f"Osoba: {anna}")
print(f"Imię: {anna.imie}, Wiek: {anna.wiek}")

# === deque - kolejka dwukierunkowa ===
print("\n=== deque ===")
kolejka = deque()
kolejka.append("pierwszy")
kolejka.append("drugi")
kolejka.appendleft("przed pierwszym")
print(f"Kolejka: {list(kolejka)}")
print(f"Pierwszy: {kolejka[0]}")
print(f"Ostatni: {kolejka[-1]}")
50/60
Moduł string: stałe tekstowe i szablony
Slajd omawia moduł string, predefiniowane stałe alfanumeryczne (ascii_letters, digits) oraz bezpieczne szablony tekstowe Template.

Zestawy znaków ASCII i klasa Template

  • Predefiniowane stałe znakowe: stałe string.ascii_letters, string.digits, string.punctuation ułatwiające walidację wejścia i generowanie haseł.
  • Szablony tekstowe (Template): bezpieczna alternatywa dla formatowania tekstu ze składnią $zmienna, chroniąca przed atakami format string.
  • Walidacja znaków: szybkie sprawdzanie czy wprowadzony ciąg składa się wyłącznie z dozwolonych znaków bez skomplikowanych regexów.
  • Generatory tokenów: połączenie stałych modułu string z modułem secrets do tworzenia kryptograficznie bezpiecznych haseł jednorazowych.
Moduł string: moduł biblioteki standardowej zawierający zestaw uniwersalnych stałych znakowych standardu ASCII oraz klasy do elastycznego podstawiania szablonów tekstu.
import string

print("=== Stałe string ===")
print(f"Litery: {string.ascii_letters}")
print(f"Małe: {string.ascii_lowercase}")
print(f"Wielkie: {string.ascii_uppercase}")
print(f"Cyfry: {string.digits}")
print(f"Interpunkcja: {string.punctuation}")

# Generowanie losowego hasła
import random

def generuj_haslo(dlugosc=12):
    """Generuje losowe hasło."""
    znaki = string.ascii_letters + string.digits + string.punctuation
    return "".join(random.choice(znaki) for _ in range(dlugosc))

print("\n=== Generowanie haseł ===")
for i in [8, 12, 16]:
    print(f"Hasło {i} znaków: {generuj_haslo(i)}")

# Template - prostsze formatowanie
print("\n=== Template ===")
szablon = string.Template("Witaj, $imie! Masz $liczba wiadomości.")
wiadomosc = szablon.substitute(imie="Anna", liczba=5)
print(wiadomosc)

# Walidacja tekstu
print("\n=== Walidacja tekstu ===")
tekst = "Test123"
print(f"Same litery? {tekst.isalpha()}")
print(f"Same cyfry? {tekst.isdigit()}")
print(f"Alfanumeryczne? {tekst.isalnum()}")
51/60
Walidacja danych wejściowych
Slajd przedstawia strategie walidacji danych: sprawdzanie typów, zakresów liczbowych, formatów oraz podejście EAFP vs LBYL.

Obrona przed błędnymi danymi i atakami

  • Filozofia EAFP: Easier to Ask for Forgiveness than Permission - preferowanie bloków try/except ponad wielokrotne sprawdzanie warunków.
  • Filozofia LBYL: Look Before You Leap - sprawdzanie stanu przed wykonaniem akcji (np. if os.path.exists(...)).
  • Walidacja typów (isinstance): funkcja isinstance(obiekt, typ) weryfikująca czy dane wejściowe spełniają wymagania kontraktu funkcji.
  • Ochrona integralności: odrzucanie niepoprawnych danych na samym brzegu aplikacji zanim trafią do bazy lub logiki biznesowej.
Filozofia EAFP (Easier to Ask for Forgiveness): naczelny paradygmat programowania w Pythonie zakładający, że kod powinien optymistycznie zakładać poprawność operacji i przechwytywać ewentualne wyjątki, co zapewnia większą czytelność i odporność na wyścigi zasobów (race conditions).
import re

def waliduj_email(email):
    """Sprawdza czy email jest poprawny."""
    wzor = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
    if re.match(wzor, email):
        return True, "Poprawny email"
    return False, "Niepoprawny email"

def waliduj_telefon(telefon):
    """Sprawdza czy numer telefonu jest poprawny."""
    # Usuń wszystkie nie-cyfry
    cyfry = re.sub(r"\D", "", telefon)
    if len(cyfry) == 9:
        return True, f"Poprawny: {cyfry}"
    return False, "Numer powinien mieć 9 cyfr"

def waliduj_wiek(wiek):
    """Sprawdza czy wiek jest realistyczny."""
    try:
        wiek_int = int(wiek)
        if wiek_int < 0:
            return False, "Wiek nie może być ujemny"
        if wiek_int > 150:
            return False, "Wiek jest niemożliwie duży"
        return True, f"Poprawny wiek: {wiek_int}"
    except ValueError:
        return False, "Wiek musi być liczbą"

def waliduj_haslo(haslo):
    """Sprawdza siłę hasła."""
    if len(haslo) < 8:
        return False, "Hasło musi mieć min. 8 znaków"
    if not re.search(r"[A-Z]", haslo):
        return False, "Hasło musi zawierać wielką literę"
    if not re.search(r"[a-z]", haslo):
        return False, "Hasło musi zawierać małą literę"
    if not re.search(r"\d", haslo):
        return False, "Hasło musi zawierać cyfrę"
    return True, "Silne hasło"

# Testy
print("=== Walidacja email ===")
for email in ["test@wp.pl", "niepoprawny", "a@b.c"]:
    poprawne, msg = waliduj_email(email)
    print(f"{email}: {msg}")

print("\n=== Walidacja hasła ===")
for haslo in ["haslo", "Haslo123", "SilneHaslo123!"]:
    poprawne, msg = waliduj_haslo(haslo)
    print(f"{haslo}: {msg}")
52/60
Porównanie metod parsowania argumentów
Slajd zestawia niskopoziomową listę sys.argv z deklaratywnym modułem argparse pod kątem czytelności, odporności i ergonomii.

sys.argv vs argparse: analiza porównawcza

  • Lista sys.argv w prostych skryptach: idealna do jedno-zadaniowych skryptów przyjmujących dokładnie jeden argument ścieżki pliku.
  • Wady sys.argv w produkcji: konieczność ręcznego pisania obsługi flag, brak pomocy --help, podatność na błędy IndexError.
  • Przewaga modułu argparse: automatyczna konwersja typów, obsługa argumentów opcjonalnych, domyślnych i generowanie dokumentacji.
  • Rekomendacja architektoniczna: wszystkie skrypty produkcyjne i narzędzia administratorskie powinny być budowane z użyciem argparse.
Architektura interfejsu CLI: standard projektowania programów konsolowych zapewniający czytelną obsługę parametrów wiersza poleceń, intuicyjną dokumentację oraz spójne kody zakończenia procesu.
# === PROSTA METODA: sys.argv ===
print("=== sys.argv ===")
import sys
print(f"Argumenty: {sys.argv}")

# Przykład prostego użycia
if len(sys.argv) > 1:
    print(f"Plik do przetworzenia: {sys.argv[1]}")

# === ZAAWANSOWANA METODA: argparse ===
print("\n=== argparse ===")
import argparse

parser = argparse.ArgumentParser(description="Kopiowanie plików")
parser.add_argument("zrodlo", help="Plik źródłowy")
parser.add_argument("cel", help="Plik docelowy")
parser.add_argument("-v", "--verbose", action="store_true", help="Tryb verbose")
parser.add_argument("-c", "--copy", type=int, default=1, help="Liczba kopii")

args = parser.parse_args()

print(f"Źródło: {args.zrodlo}")
print(f"Cel: {args.cel}")
print(f"Verbose: {args.verbose}")
print(f"Liczba kopii: {args.copy}")

# Uruchom:
# python skrypt.py plik.txt kopia.txt -v -c 3
53/60
Moduł csv: przetwarzanie plików CSV
Slajd omawia moduł csv, obiekty csv.reader, csv.writer oraz operacje na słownikach z wykorzystaniem DictReader i DictWriter.

Czytanie i zapis danych tabelarycznych

  • Format CSV (Comma Separated Values): uniwersalny standard zapisu danych tabelarycznych wymieniany pomiędzy bazami a arkuszami kalkulacyjnymi.
  • Funkcje csv.reader i csv.writer: podstawowe narzędzia do sekwencyjnego odczytu i zapisu wierszy w postaci list pól tekstowych.
  • Klasy DictReader i DictWriter: odczytują i zapisują wiersze jako słowniki na podstawie nagłówków kolumn (niezwykle czytelny kod).
  • Parametr newline='': bezwzględny wymóg otwierania pliku z parametrem newline='' w instrukcji with open() w celu uniknięcia pustych linii w Windows.
Moduł csv: standardowy moduł Pythona implementujący bezpieczny odczyt i zapis danych w formacie CSV zgodnie z normą RFC 4180, automatycznie obsługujący znaki ucieczki, separatory oraz cudzysłowy w polach tekstowych.
import csv

# === ZAPIS DO CSV ===
print("=== Zapis CSV ===")
dane = [
    ["Imię", "Wiek", "Miasto"],
    ["Anna", "20", "Warszawa"],
    ["Bartek", "25", "Kraków"],
    ["Celina", "30", "Gdańsk"]
]

with open("osoby.csv", "w", newline="", encoding="utf-8") as plik:
    writer = csv.writer(plik)
    writer.writerows(dane)
print("Zapisano do osoby.csv")

# === ODCZYT Z CSV ===
print("\n=== Odczyt CSV ===")
with open("osoby.csv", "r", encoding="utf-8") as plik:
    reader = csv.reader(plik)
    for wiersz in reader:
        print(wiersz)

# === ODCZYT JAKO SŁOWNIKI ===
print("\n=== Odczyt jako słowniki ===")
with open("osoby.csv", "r", encoding="utf-8") as plik:
    reader = csv.DictReader(plik)
    for wiersz in reader:
        print(f"{wiersz['Imię']} z {wiersz['Miasto']} ma {wiersz['Wiek']} lat")

# === ZAPIS ZE SŁOWNIKÓW ===
print("\n=== Zapis ze słowników ===")
with open("nowe.csv", "w", newline="", encoding="utf-8") as plik:
    fieldnames = ["Imię", "Wiek", "Miasto"]
    writer = csv.DictWriter(plik, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerow({"Imię": "Adam", "Wiek": "22", "Miasto": "Poznań"})
print("Zapisano do nowe.csv")
54/60
Moduł statistics: podstawowa analityka danych
Slajd przedstawia moduł statistics, wyliczanie średniej arytmetycznej, mediany, odchylenia standardowego oraz mody.

Obliczenia statystyczne bez zewnętrznych bibliotek

  • Średnia arytmetyczna (mean): funkcja statistics.mean(dane) błyskawicznie wylicza wartość średnią z sekwencji liczb.
  • Mediana (median): wartość środkowa zbioru, odporna na obecność anomalii i wartości skrajnych w danych pomiarowych.
  • Odchylenie standardowe (stdev): miara rozproszenia wyników wokół wartości średniej, kluczowa w audycie wydajności serwerów.
  • Moda (mode): najczęściej występująca wartość w badanym zbiorze próbek telemetrycznych.
Moduł statistics: wbudowany moduł biblioteki standardowej Pythona dostarczający funkcje do matematycznej analizy statystycznej dla danych liczbowych, eliminujący konieczność instalacji ciężkich pakietów zewnętrznych w prostych skryptach.
import statistics

# Dane przykładowe - wyniki egzaminu
wyniki = [85, 90, 78, 92, 88, 76, 95, 89, 84, 91]

print("=== Analiza wyników egzaminu ===")
print(f"Wyniki: {wyniki}")

srednia = statistics.mean(wyniki)
print(f"Średnia: {srednia:.2f}")

mediana = statistics.median(wyniki)
print(f"Mediana: {mediana}")

odchylenie = statistics.stdev(wyniki)
print(f"Odchylenie standardowe: {odchylenie:.2f}")

wariancja = statistics.variance(wyniki)
print(f"Wariancja: {wariancja:.2f}")

# Trywialne dane
dane_nieparzyste = [1, 2, 3, 4, 5, 6, 7]
print(f"\nDane nieparzyste: {dane_nieparzyste}")
print(f"Średnia: {statistics.mean(dane_nieparzyste)}")
print(f"Mediana: {statistics.median(dane_nieparzyste)}")

# Kwartyle
print("\n=== Kwantyle ===")
kwartyle = statistics.quantiles(wyniki, n=4)
print(f"Kwartyle: {kwartyle}")

# Moda (najczęstsza wartość, zwraca pierwszą napotkaną)
# W Pythonie 3.8+ mode() zwraca pierwszą napotkaną wartość, gdy jest ich kilka
wartosci = [1, 2, 2, 2, 3, 4, 4, 4, 5]
print(f"\nWartości: {wartosci}")
print(f"Moda (najczęstsza): {statistics.mode(wartosci)}")
55/60
Rekursywne trawersowanie katalogów: os.walk()
Slajd omawia generator os.walk(), trójkę wartości (root, dirs, files) oraz masowe operacje na strukturach dyskowych.

Głębokie przeszukiwanie drzewa folderów

  • Generator os.walk(): rekursywnie odwiedza katalog bazowy oraz wszystkie zagnieżdżone podfoldery na dowolną głębokość.
  • Trójka wartości w pętli: w każdym kroku pętli generator zwraca krotkę: bieżący folder (root), listę podfolderów (dirs) oraz listę plików (files).
  • Modyfikacja listy dirs: modyfikacja listy dirs w locie pozwala na wykluczenie określonych podkatalogów (np. .git, node_modules) z przeszukiwania.
  • Łączenie ścieżek: użycie os.path.join(root, plik) lub Path(root) / plik do budowania pełnych bezwzględnych ścieżek dostępu.
Generator os.walk(): funkcja biblioteki standardowej generująca nazwy plików i katalogów w drzewie systemu plików poprzez trawersowanie w głąb (top-down) lub od dołu (bottom-up), minimalizująca zużycie pamięci operacyjnej.
import os

# Rekurencyjne przechodzenie katalogów
print("=== Struktura katalogów ===")
for katalog, podkatalogi, pliki in os.walk(".", topdown=True):
    # Poziom zagłębienia
    glebokosc = katalog.count(os.sep)
    wciecie = "  " * glebokosc
    
    print(f"{wciecie}{os.path.basename(katalog) or '.'}/")
    
    # Podkatalogi
    for podkatalog in podkatalogi:
        print(f"{wciecie}  [K] {podkatalog}/")
    
    # Pliki
    for plik in pliki[:5]:  # max 5 plików na katalog
        print(f"{wciecie}  [P] {plik}")
    if len(pliki) > 5:
        print(f"{wciecie}  ... i {len(pliki) - 5} więcej plików")

# Wyszukiwanie plików określonego typu
print("\n=== Wyszukiwanie plików .py ===")
pliki_py = []
for katalog, podkatalogi, pliki in os.walk("."):
    for plik in pliki:
        if plik.endswith(".py"):
            pliki_py.append(os.path.join(katalog, plik))

print(f"Znaleziono {len(pliki_py)} plików .py:")
for p in pliki_py[:10]:
    print(f"  {p}")
56/60
Debugowanie kodu: moduł pdb
Slajd przedstawia wbudowany debugger pdb, funkcję breakpoint(), pułapki (breakpoints) oraz komendy inspekcji n, s, c, p.

Interaktywny debugger kroków w Pythonie

  • Wbudowana funkcja breakpoint(): zatrzymuje wykonywanie programu w wybranym wierszu i uruchamia interaktywną sesję debugera w konsoli.
  • Podstawowe komendy debugera: n (next - następna linia), s (step into - wejście do funkcji), c (continue - kontynuacja biegu), q (quit - wyjście).
  • Inspekcja zmiennych (p i pp): komenda p wyrażenie wypisuje bieżącą wartość zmiennej; pp dokonuje estetycznego wydruku struktur danych.
  • Diagnoza w auli i na produkcji: niezastąpione narzędzie do analizy trudnych do odtworzenia błędów logicznych bezpośrednio na serwerze.
Debugger pdb (Python Debugger): wbudowany w Pythona interaktywny system śledzenia wykonania kodu źródłowego, umożliwiający zatrzymywanie wątku na pułapkach, inspekcję ramek stosu oraz ewaluację wyrażeń w kontekście bieżącej funkcji.
# === PROSTY PRZYKŁAD DEBUGOWANIA ===
# Uruchom z: python -m pdb debug_example.py
# Lub dodaj breakpoint() w kodzie

def oblicz_silnie(n):
    """Oblicza silnię (n!)."""
    if n < 0:
        raise ValueError("Silnia nie jest określona dla liczb ujemnych")
    if n == 0 or n == 1:
        return 1
    
    wynik = 1
    for i in range(2, n + 1):
        wynik = wynik * i
    return wynik

def debuguj_silnie():
    """Demonstruje debugowanie."""
    liczby = [5, 3, 7, -1]
    
    for liczba in liczby:
        print(f"Obliczam silnię z {liczba}...")
        # breakpoint()  # <-- Odkomentuj aby debugować
        try:
            wynik = oblicz_silnie(liczba)
            print(f"  {liczba}! = {wynik}")
        except ValueError as e:
            print(f"  Błąd: {e}")

# Uruchomienie
if __name__ == "__main__":
    debuguj_silnie()

# === WSKAZÓWKI DEBUGOWANIA ===
# 1. Uruchom: python -m pdb skrypt.py
# 2. (Pdb) l  - wyświetl kod
# 3. (Pdb) n  - następna linia
# 4. (Pdb) p zmienna - pokaż zmienną
# 5. (Pdb) c  - kontynuuj
# 6. (Pdb) q  - wyjdź
57/60
Testowanie oprogramowania: framework pytest
Slajd omawia kulturę testowania, asercje instrukcją assert, strukturę testów oraz uruchamianie frameworka pytest.

Automatyzacja weryfikacji poprawności i testy jednostkowe

  • Dlaczego testujemy kod?: automatyczne testy gwarantują, że nowe modyfikacje nie popsują dotychczas działających funkcji (regresja).
  • Prostota asercji (assert): pytest wykorzystuje zwykłą instrukcję assert warunek, bez konieczności dziedziczenia po klasach TestCase.
  • Konwencja nazewnicza: pliki testowe nazywa się test_*.py, a funkcje testowe test_*(), co umożliwia ich automatyczne odkrywanie.
  • Uruchamianie w konsoli: wpisanie samego polecenia pytest w katalogu projektu automatycznie wykonuje wszystkie testy i generuje raport.
Testy jednostkowe (unit testing / pytest): metodyka inżynierii oprogramowania polegająca na pisaniu niezależnych programów testowych sprawdzających poprawność najmniejszych jednostek kodu (pojedynczych funkcji lub metod) w izolacji od reszty systemu.
# === PLIK: kalkulator.py ===

def dodaj(a, b):
    return a + b

def odejmij(a, b):
    return a - b

def pomnóż(a, b):
    return a * b

def podziel(a, b):
    if b == 0:
        raise ZeroDivisionError("Nie można dzielić przez zero!")
    return a / b

# === PLIK: test_kalkulator.py ===

import pytest
from kalkulator import dodaj, odejmij, pomnóż, podziel

def test_dodaj():
    assert dodaj(2, 3) == 5
    assert dodaj(-1, 1) == 0
    assert dodaj(0, 0) == 0

def test_odejmij():
    assert odejmij(5, 3) == 2
    assert odejmij(3, 5) == -2

def test_pomnóż():
    assert pomnóż(3, 4) == 12
    assert pomnóż(0, 100) == 0

def test_podziel():
    assert podziel(10, 2) == 5
    assert podziel(9, 3) == 3

def test_podziel_przez_zero():
    with pytest.raises(ZeroDivisionError):
        podziel(10, 0)

# Uruchomienie testów:
# pytest test_kalkulator.py -v
58/60
Sztuczki i idiomy języka Python
Slajd prezentuje zaawansowane idiomy języka Python: rozpakowywanie sekwencji (unpacking), zamiana zmiennych bez bufora oraz operatory scalania |.

Eleganckie konstrukcje: rozpakowywanie, zip i dictionary unpacking

  • Zamiana zmiennych w jednej linii: idiom a, b = b, a natychmiast zamienia wartości dwóch zmiennych bez konieczności tworzenia zmiennej tymczasowej.
  • Rozpakowywanie z gwiazdką: konstrukcja pierwszy, *reszta, ostatni = kolekcja pozwala na intuicyjne dzielenie sekwencji danych.
  • Łączenie słowników (operator |): wprowadzony w Pythonie 3.9 operator polaczone = slownik1 | slownik2 elegancko scala tablice asocjacyjne.
  • Formatowanie kolekcji: stosowanie generatorów wewnątrz funkcji sum(), any() oraz all() w celu optymalizacji pamięciowej obliczeń.
Pythoniczny kod (idiomatic / pythonic code): kod źródłowy wykorzystujący unikalne, eleganckie i zwięzłe mechanizmy składniowe języka Python, zgodny z filozofią The Zen of Python (PEP 20).
# === ZAMIANA ZMIENNYCH BEZ TYMCZASOWEJ ===
print("=== Zamiana zmiennych ===")
a, b = 5, 10
print(f"Przed: a={a}, b={b}")
a, b = b, a
print(f"Po: a={a}, b={b}")

# === OPERATOR TRÓJSKLADNIKOWY ===
print("\n=== Operator trójskładnikowy ===")
wiek = 20
status = "pełnoletni" if wiek >= 18 else "niepełnoletni"
print(f"Status: {status}")

# === ROZPAKOWANIE KROTKILISTY ===
print("\n=== Rozpakowanie ===")
pierwszy, *reszta, ostatni = [1, 2, 3, 4, 5]
print(f"Pierwszy: {pierwszy}, Reszta: {reszta}, Ostatni: {ostatni}")

# === ODWRÓCENIE ===
print("\n=== Odwracanie ===")
lista = [1, 2, 3, 4, 5]
print(f"Odwrócona lista: {lista[::-1]}")
tekst = "Python"
print(f"Odwrócony tekst: {tekst[::-1]}")

# === ANY i ALL ===
print("\n=== any() i all() ===")
liczby = [2, 4, 6, 8]
print(f"Wszystkie parzyste? {all(x % 2 == 0 for x in liczby)}")
print(f"Co najmniej jedna parzysta? {any(x % 2 == 0 for x in liczby)}")

# === ENUMERATE z wieloma listami ===
print("\n=== Zip i enumerate ===")
imiona = ["Anna", "Bartek", "Celina"]
wieki = [20, 25, 30]
for i, (imie, wiek) in enumerate(zip(imiona, wieki)):
    print(f"{i+1}. {imie} ma {wiek} lat")
59/60
Środowiska wirtualne: moduł venv
Slajd wyjaśnia konieczność izolacji bibliotek, tworzenie środowiska python -m venv .venv oraz aktywację i instalację pakietów pip.

Izolacja zależności projektowych i pip

  • Problem globalnych pakietów: instalowanie bibliotek globalnie prowadzi do konfliktów wersji (tzw. dependency hell) pomiędzy projektami.
  • Tworzenie środowiska (venv): polecenie python -m venv .venv tworzy niezależną kopię interpretera i katalogu bibliotek w folderze projektu.
  • Aktywacja środowiska: uruchomienie skryptu aktywującego: source .venv/bin/activate (Linux) lub .venv\Scripts\Activate.ps1 (Windows).
  • Plik requirements.txt: zapisywanie zależności poleceniem pip freeze > requirements.txt gwarantuje powtarzalność wdrożeń produkcyjnych.
Środowisko wirtualne (Virtual Environment / venv): samodzielne, odizolowane drzewo katalogów zawierające własną kopię interpretera Pythona oraz dedykowany katalog pakietów site-packages, uniemożliwiające powstawanie konfliktów wersji bibliotek.
# === TWORZENIE ŚRODOWISKA WIRTUALNEGO ===

# Linux/macOS
$ python3 -m venv .venv

# Windows
C:\> python -m venv .venv

# === AKTYWACJA ===

# Linux/macOS
$ source .venv/bin/activate
(.venv) $

# Windows PowerShell
PS C:\> .\.venv\Scripts\Activate.ps1
(.venv) PS C:\>

# Windows CMD
C:\> .\.venv\Scripts\activate.bat
(.venv) C:\>

# === INSTALACJA PAKIETÓW ===

(.venv) $ pip install requests
(.venv) $ pip install pytest

# === ZAPISYWANIE ZALEŻNOŚCI ===

(.venv) $ pip freeze > requirements.txt

# Plik requirements.txt wygląda tak:
# requests==2.31.0
# pytest==7.4.0

# === INSTALACJA Z PLIKU ===

(.venv) $ pip install -r requirements.txt

# === DEZAKTYWACJA ===

(.venv) $ deactivate
$
60/60
Podsumowanie kursu i perspektywy rozwoju
Slajd rekapituluje fundamenty opanowane w trakcie kursu Pythona oraz wskazuje dalsze kierunki rozwoju: FastAPI, Docker, chmura i Data Science.

Rekapitulacja wiedzy i zaawansowane ścieżki kariery

  • Opanowany warsztat programistyczny: biegła znajomość struktur danych, pisania modularnych funkcji, obsługi plików, wyjątków i biblioteki standardowej.
  • Dobre nawyki programistyczne: stosowanie standardu PEP 8, menedżerów kontekstu with, środowisk venv oraz automatycznych testów jednostkowych.
  • Ścieżki dalszego rozwoju: specjalizacja w backendzie (FastAPI/Django), automatyzacji chmurowej (AWS SDK, Azure SDK) lub Data Science (Pandas).
  • Kolejny etap edukacji: przejście do części 6 kursu poświęconej tworzeniu interaktywnych aplikacji internetowych w technologiach HTML5 i JavaScript.
Inżynier oprogramowania Python (Python Software Engineer): rolę specjalisty IT tworzącego czytelne, bezpieczne i skalowalne aplikacje oraz systemy automatyzacji w oparciu o ekosystem Pythona i zasady inżynierii oprogramowania.
+----------------------------------+
|      GRATULACJE!                |
|                                  |
|  Ukończyłeś kurs podstaw Pythona |
|                                  |
|  Teraz możesz:                   |
|  [x] Pisać własne skrypty        |
|  [x] Automatyzować zadania       |
|  [x] Przetwarzać pliki           |
|  [x] Analizować dane             |
|                                  |
|  Powodzenia w dalszej nauce!     |
|                                  |
+----------------------------------+