Języki programowania

Uniwersytet SWPS

Psychologia i informatyka

"Python to język programowania, który pozwala pracować szybciej i efektywniej integrować systemy." - Python Software Foundation

1. Wprowadzenie i Przygotowanie Środowiska

Instalacja i konfiguracja interpretera Pythona

 

  • Python można pobrać z python.org
  • Wybierz najnowszą stabilną wersję (Python 3.11+)
  • Podczas instalacji zaznacz 'Add Python to PATH'
  • Weryfikacja instalacji: python --version

Wybór edytora kodu

 

Popularne edytory dla Python:

  • PyCharm - profesjonalne IDE
  • VS Code - lekki, wszechstronny
  • Jupyter Notebook - interaktywne notatniki
  • IDLE - wbudowany w Pythona

Ciekawostka: Guido van Rossum, twórca Pythona, nazwał język na cześć grupy komediowej Monty Python!

2. Podstawy Programowania w Pythonie

Zmienne i proste obliczenia

Zmienne to 'pojemniki' na dane. W Pythonie nie trzeba deklarować typu!

# Zmienne i obliczenia
x = 10
y = 20
suma = x + y           # 30
roznica = y - x        # 10
iloczyn = x * y        # 200
iloraz = y / x         # 2.0
potega = x ** 2        # 100 (x do kwadratu)
reszta = y % 3         # 2 (reszta z dzielenia)

2. Podstawy Programowania w Pythonie

Zmienne i proste obliczenia

Zmienne to 'pojemniki' na dane. W Pythonie nie trzeba deklarować typu!

Typy Danych - Fundamenty

# int - liczby całkowite
wiek = 25
temperatura = -5

# float - liczby zmiennoprzecinkowe
cena = 19.99
pi = 3.14159

# str - łańcuchy znaków
imie = "Anna"
miasto = 'Kraków'  # można używać ' lub "
wielolinia = """Tekst
w wielu
liniach"""

# bool - wartości logiczne
jest_studentem = True
ma_prawo_jazdy = False

Operacje na Łańcuchach Znaków

# Łączenie stringów
imie = "Jan"
nazwisko = "Kowalski"
pelne_imie = imie + " " + nazwisko  # "Jan Kowalski"

# f-stringi (formatowanie)
wiek = 30
info = f"Mam na imię {imie} i mam {wiek} lat"

# Metody stringów
tekst = "python jest świetny"
print(tekst.upper())        # PYTHON JEST ŚWIETNY
print(tekst.capitalize())   # Python jest świetny
print(tekst.replace("python", "Python"))  # Python jest świetny
print(tekst.split())        # ['python', 'jest', 'świetny']
print(len(tekst))           # 19 (długość)

Konwersja Typów Danych

# Konwersja między typami
wiek_str = "25"
wiek_int = int(wiek_str)      # string → int

cena_float = 19.99
cena_int = int(cena_float)    # 19 (ucina część dziesiętną!)

liczba = 42
tekst = str(liczba)           # int → string

# Sprawdzanie typu
print(type(wiek_int))         # 
print(isinstance(wiek_int, int))  # True

# UWAGA: Typowe błędy!
# int("19.99")  # ValueError! Najpierw float("19.99")
# int("sto")    # ValueError! Nie można przekonwertować

Typowe Błędy i Ich Naprawa

# BŁĄD 1: Dzielenie przez zero
# wynik = 10 / 0  # ZeroDivisionError
# Rozwiązanie: sprawdzaj przed dzieleniem
dzielnik = 0
if dzielnik != 0:
    wynik = 10 / dzielnik

# BŁĄD 2: Łączenie różnych typów
# wiadomosc = "Mam " + 25 + " lat"  # TypeError
# Rozwiązanie: konwersja na string
wiadomosc = "Mam " + str(25) + " lat"
# LUB użyj f-stringa
wiadomosc = f"Mam {25} lat"

# BŁĄD 3: Literówki w nazwach zmiennych
# imię = "Jan"  # Unicode w nazwie - lepiej unikać
# print(imie)  # NameError
imie = "Jan"  # Lepiej bez polskich znaków w nazwach

3. Struktury Kontrolne

Instrukcje Warunkowe (if, elif, else)

# Podstawowa instrukcja if
wiek = 20
if wiek >= 18:
    print("Jesteś pełnoletni")
# if-else
temperatura = 15
if temperatura > 20:
    print("Jest ciepło")
else:
    print("Jest chłodno")
# if-elif-else (wiele warunków)
ocena = 85
if ocena >= 90:
    print("Ocena: Bardzo dobry")
elif ocena >= 75:
    print("Ocena: Dobry")
elif ocena >= 60:
    print("Ocena: Dostateczny")
else:
    print("Ocena: Niedostateczny")

Operatory Porównania i Logiczne

# Operatory porównania
x = 10
y = 20
print(x == y)   # False (równe?)
print(x != y)   # True (różne?)
print(x < y)    # True (mniejsze?)
print(x <= y)   # True (mniejsze lub równe?)

# Operatory logiczne: and, or, not
wiek = 25
ma_dowod = True

# AND - oba warunki muszą być prawdziwe
if wiek >= 18 and ma_dowod:
    print("Może prowadzić samochód")

# OR - przynajmniej jeden warunek prawdziwy
jest_weekend = True
jest_urlop = False
if jest_weekend or jest_urlop:
    print("Można odpocząć!")

# NOT - negacja
if not jest_urlop:
    print("Trzeba iść do pracy")

Pętla FOR - Iteracja po Sekwencjach

# Pętla for przez listę
owoce = ["jabłko", "banan", "gruszka"]
for owoc in owoce:
    print(f"Lubię {owoc}")

# Pętla for z range()
for i in range(5):  # 0, 1, 2, 3, 4
    print(f"Liczba: {i}")

# range() z początkiem i końcem
for i in range(2, 6):  # 2, 3, 4, 5
    print(i)

# range() z krokiem
for i in range(0, 10, 2):  # 0, 2, 4, 6, 8
    print(i)

# enumerate() - iteracja z indeksem
for indeks, owoc in enumerate(owoce):
    print(f"{indeks}: {owoc}")

Pętla WHILE i Sterowanie (break, continue)

# Pętla while - wykonuje się, gdy warunek prawdziwy
licznik = 0
while licznik < 5:
    print(licznik)
    licznik += 1

# BREAK - przerywa pętlę
for i in range(10):
    if i == 5:
        break  # Zatrzymuje pętlę
    print(i)  # Wypisze: 0, 1, 2, 3, 4

# CONTINUE - przechodzi do następnej iteracji
for i in range(5):
    if i == 2:
        continue  # Pomija resztę kodu dla i=2
    print(i)  # Wypisze: 0, 1, 3, 4

# Praktyczny przykład: walidacja hasła
while True:
    haslo = input("Podaj hasło (min 8 znaków): ")
    if len(haslo) <= 8:
        break
    print("Hasło za krótkie!")

4. Struktury Danych

LISTY - Zmienne, Uporządkowane Kolekcje

# Tworzenie listy
liczby = [1, 2, 3, 4, 5]
mieszana = [1, "tekst", 3.14, True]

# Dodawanie elementów
liczby.append(6)           # Dodaje na koniec
liczby.insert(0, 0)        # Wstawia na pozycję 0

# Usuwanie elementów
liczby.remove(3)           # Usuwa pierwszą wartość 3
ostatni = liczby.pop()     # Usuwa i zwraca ostatni element
del liczby[0]              # Usuwa element na pozycji 0

# Operacje
print(len(liczby))         # Długość listy
print(2 in liczby)         # Sprawdza czy 2 jest na liście
print(liczby.count(2))     # Ile razy 2 występuje
liczby.sort()              # Sortuje listę
liczby.reverse()           # Odwraca kolejność

KROTKI (Tuples) - Niezmienne Sekwencje

# Krotki - podobne do list, ale NIEZMIENNE
punkt = (10, 20)
osoba = ("Jan", "Kowalski", 30)

# Dostęp do elementów (jak w listach)
x = punkt[0]  # 10
y = punkt[1]  # 20

# Rozpakowanie krotki
imie, nazwisko, wiek = osoba
print(f"{imie} ma {wiek} lat")

# Krotki są niezmienne!
# punkt[0] = 15  # TypeError! Nie można zmienić

# Kiedy używać krotek?
# - Dane, które nie powinny się zmieniać (współrzędne, daty)
# - Zwracanie wielu wartości z funkcji
# - Klucze w słownikach (listy nie mogą być kluczami!)

# Ciekawostka: krotka 1-elementowa wymaga przecinka!
krotka = (5,)  # To jest krotka
nie_krotka = (5)  # To jest int!

SŁOWNIKI - Pary Klucz-Wartość

# Słownik - mapowanie klucz → wartość
student = {
    "imie": "Anna",
    "nazwisko": "Nowak",
    "wiek": 22,
    "oceny": [4, 5, 4, 5]
}

# Dostęp do wartości
print(student["imie"])              # Anna
print(student.get("wiek"))          # 22
print(student.get("email", "brak")) # Zwróci "brak" jeśli nie ma

# Dodawanie/modyfikacja
student["email"] = "anna@example.com"
student["wiek"] = 23

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

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

# Przydatne metody
print(student.keys())    # Wszystkie klucze
print(student.values())  # Wszystkie wartości

ZBIORY (Sets) - Unikalne Elementy

# Zbiór - nieuporządkowana kolekcja unikalnych elementów
liczby = {1, 2, 3, 4, 5}
kolory = {"czerwony", "niebieski", "zielony"}

# Automatycznie usuwa duplikaty!
duplikaty = {1, 2, 2, 3, 3, 3}
print(duplikaty)  # {1, 2, 3}

# Operacje na zbiorach
liczby.add(6)         # Dodaje element
liczby.remove(1)      # Usuwa element (błąd jeśli nie ma)
liczby.discard(10)    # Usuwa element (bez błędu)

# Operacje matematyczne na zbiorach
A = {1, 2, 3, 4}
B = {3, 4, 5, 6}
print(A | B)   # Suma (union): {1, 2, 3, 4, 5, 6}
print(A &amp; B)   # Przecięcie (intersection): {3, 4}
print(A - B)   # Różnica: {1, 2}

# Sprawdzanie przynależności (bardzo szybkie!)
print(3 in A)  # True

Stosy i Kolejki - Zaawansowane Struktury

from collections import deque

# STOS (Stack) - LIFO (Last In, First Out)
# "Ostatni wszedł, pierwszy wyszedł" - jak stos talerzy
stos = []
stos.append(1)    # Kładziemy na stos
stos.append(2)
stos.append(3)
print(stos.pop()) # 3 - zdejmujemy ostatni

# KOLEJKA (Queue) - FIFO (First In, First Out)
# "Pierwszy wszedł, pierwszy wyszedł" - jak kolejka w sklepie
kolejka = deque()
kolejka.append(1)      # Dodajemy na koniec
kolejka.append(2)
kolejka.append(3)
print(kolejka.popleft())  # 1 - bierzemy pierwszy

# Praktyczne zastosowanie: historia poleceń (Undo/Redo)
historia = []
historia.append("Wpisałem tekst")
historia.append("Usunąłem słowo")
ostatnia_akcja = historia.pop()  # Cofnij ostatnią akcję

5. Unpacking - Rozpakowywanie 

Podstawy Unpacking

# Unpacking to rozpakowywanie wartości z kolekcji do zmiennych

# Podstawowy unpacking z listy/krotki
punkt = (10, 20)
x, y = punkt
print(x, y)  # 10 20
# Unpacking listy
dane = ["Jan", "Kowalski", 30]
imie, nazwisko, wiek = dane
print(f"{imie} {nazwisko}, {wiek} lat")

# Unpacking w pętli for
osoby = [("Anna", 25), ("Piotr", 30), ("Maria", 28)]
for imie, wiek in osoby:
    print(f"{imie}: {wiek} lat")
# Zamiana wartości zmiennych (bez trzeciej zmiennej!)
a = 5
b = 10
a, b = b, a  # Zamiana miejscami
print(a, b)  # 10 5
# Unpacking z funkcji zwracającej krotkę
def get_coordinates():
    return (100, 200, 300)
x, y, z = get_coordinates()
print(x, y, z)  # 100 200 300

Extended Unpacking - Operator *

# Operator * (gwiazdka) - zbiera pozostałe elementy

# Pierwsza i reszta
liczby = [1, 2, 3, 4, 5]
pierwsza, *reszta = liczby
print(pierwsza)  # 1
print(reszta)    # [2, 3, 4, 5]

# Pierwsza, ostatnia i środek
pierwszy, *srodek, ostatni = liczby
print(pierwszy)  # 1
print(srodek)    # [2, 3, 4]
print(ostatni)   # 5

# Ignorowanie elementów
a, *_, b = [1, 2, 3, 4, 5]
print(a, b)  # 1 5

# Unpacking z różną liczbą elementów
def suma_pierwszych_dwoch(*args):
    pierwszy, drugi, *pozostale = args
    return pierwszy + drugi

print(suma_pierwszych_dwoch(10, 20, 30, 40))  # 30

# Unpacking zagnieżdżonych struktur
dane = [("Jan", (25, "Warszawa")), ("Anna", (30, "Kraków"))]
for imie, (wiek, miasto) in dane:
    print(f"{imie}, {wiek} lat, {miasto}")

Unpacking Słowników

# Unpacking słowników z **

# Łączenie słowników
slownik1 = {"a": 1, "b": 2}
slownik2 = {"c": 3, "d": 4}
polaczony = {**slownik1, **slownik2}
print(polaczony)  # {'a': 1, 'b': 2, 'c': 3, 'd': 4}

# Nadpisywanie wartości
domyslne = {"theme": "dark", "lang": "pl", "size": 12}
uzytkownik = {"theme": "light", "size": 14}
config = {**domyslne, **uzytkownik}
print(config)  # {'theme': 'light', 'lang': 'pl', 'size': 14}

# Unpacking w funkcjach
def utworz_profil(imie, wiek, miasto):
    return f"{imie}, {wiek} lat, {miasto}"

dane = {"imie": "Jan", "wiek": 30, "miasto": "Warszawa"}
profil = utworz_profil(**dane)
print(profil)  # Jan, 30 lat, Warszawa

# Rozpakowywanie items()
osoba = {"imie": "Anna", "wiek": 25}
for klucz, wartosc in osoba.items():
    print(f"{klucz}: {wartosc}")

Unpacking w Funkcjach - *args i **kwargs

# *args - argumenty pozycyjne (tuple)
def suma(*args):
    """Sumuje dowolną liczbę argumentów."""
    return sum(args)

print(suma(1, 2, 3))           # 6
print(suma(10, 20, 30, 40))    # 100

# **kwargs - argumenty nazwane (dictionary)
def info_osoby(**kwargs):
    """Wyświetla informacje o osobie."""
    for klucz, wartosc in kwargs.items():
        print(f"{klucz}: {wartosc}")

info_osoby(imie="Jan", wiek=30, miasto="Warszawa")
# imie: Jan
# wiek: 30
# miasto: Warszawa

# Łączenie *args i **kwargs
def zaawansowana_funkcja(a, b, *args, **kwargs):
    print(f"Pozycyjne: a={a}, b={b}")
    print(f"Dodatkowe pozycyjne: {args}")
    print(f"Nazwane: {kwargs}")

zaawansowana_funkcja(1, 2, 3, 4, 5, x=10, y=20)
# Pozycyjne: a=1, b=2
# Dodatkowe pozycyjne: (3, 4, 5)
# Nazwane: {'x': 10, 'y': 20}

Unpacking w Wywołaniach Funkcji

# Rozpakowywanie przy wywołaniu funkcji

def oblicz(a, b, c):
    return a + b * c

# Bez unpacking
wynik1 = oblicz(1, 2, 3)
print(wynik1)  # 7

# Z unpacking listy/krotki
liczby = [1, 2, 3]
wynik2 = oblicz(*liczby)
print(wynik2)  # 7

# Unpacking słownika
def przedstaw_sie(imie, nazwisko, wiek):
    return f"Jestem {imie} {nazwisko}, mam {wiek} lat"

dane = {"imie": "Jan", "nazwisko": "Kowalski", "wiek": 30}
tekst = przedstaw_sie(**dane)
print(tekst)

# Praktyczny przykład: przekazywanie do print()
elementy = ["jabłko", "banan", "gruszka"]
print(*elementy)  # jabłko banan gruszka
print(*elementy, sep=", ")  # jabłko, banan, gruszka

# Łączenie list
lista1 = [1, 2, 3]
lista2 = [4, 5, 6]
lista3 = [7, 8, 9]
wszystkie = [*lista1, *lista2, *lista3]
print(wszystkie)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]

Praktyczne Zastosowania Unpacking

# 1. Parsowanie danych CSV
dane_csv = "Jan,Kowalski,30,Warszawa"
imie, nazwisko, wiek, miasto = dane_csv.split(",")

# 2. Paginacja - pierwsza strona i reszta
wszystkie_strony = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
pierwsza, *pozostale = wszystkie_strony

# 3. Rozdzielanie nagłówków i danych
plik_csv = [
    ["Imię", "Nazwisko", "Wiek"],
    ["Jan", "Kowalski", "30"],
    ["Anna", "Nowak", "25"]
]
naglowki, *wiersze = plik_csv

# 4. Tworzenie konfiguracji z wartościami domyślnymi
def polacz_config(**config):
    domyslne = {"debug": False, "port": 8080, "host": "localhost"}
    return {**domyslne, **config}

moja_config = polacz_config(debug=True, port=3000)
# {'debug': True, 'port': 3000, 'host': 'localhost'}

# 5. Decorator pattern
def moj_decorator(func):
    def wrapper(*args, **kwargs):
        print("Przed wywołaniem")
        wynik = func(*args, **kwargs)
        print("Po wywołaniu")
        return wynik
    return wrapper

@moj_decorator
def przywitaj(imie):
    print(f"Cześć, {imie}!")

przywitaj("Jan")

Zaawansowane Techniki i Pułapki

 

DOBRE PRAKTYKI:

  1. Unpacking zwiększa czytelność kodu
    • Zamiast: x = punkt[0], y = punkt[1]
    • Użyj: x, y = punkt
  2. Używaj _ dla ignorowanych wartości
    • pierwszy, _, trzeci = [1, 2, 3]
  3. * może wystąpić tylko raz w unpacking
    • a, *b, *c = [1,2,3] # BŁĄD!
  4. Liczba zmiennych musi pasować (bez *)
    • a, b = [1, 2, 3] # ValueError!
    • a, b, *c = [1, 2, 3] # OK: c=[3]

 

Zaawansowane Techniki i Pułapki

 

PUŁAPKI:

  • Unpacking zagnieżdżonych struktur może być mało czytelny
  • * tworzy listę, nawet dla pustej sekwencji
  • ** działa tylko ze słownikami (mapowaniami)
  • Kolejność w **kwargs nie jest gwarantowana (Python < 3.7)

Kiedy używać unpacking?

  • Zwracanie wielu wartości z funkcji
  • Iteracja po parach klucz-wartość
  • Przekazywanie parametrów do funkcji
  • Łączenie kolekcji
  • Zamiana wartości bez zmiennej tymczasowej

 

6. Obsługa Błędów

Rodzaje Błędów w Pythonie

 

  • SyntaxError - błąd składni (literówki, brakujące dwukropki)
  • NameError - użycie niezdefiniowanej zmiennej
  • TypeError - operacja na złym typie danych
  • ValueError - dobry typ, zła wartość
  • ZeroDivisionError - dzielenie przez zero
  • IndexError - indeks poza zakresem
  • KeyError - brak klucza w słowniku
  • FileNotFoundError - brak pliku

Try/Except - Obsługa Wyjątków

# Podstawowa obsługa błędów
try:
    liczba = int(input("Podaj liczbę: "))
    wynik = 10 / liczba
    print(f"Wynik: {wynik}")
except ValueError:
    print("To nie jest liczba!")
except ZeroDivisionError:
    print("Nie można dzielić przez zero!")

# Złapanie dowolnego błędu
try:
    # ryzykowny kod
    plik = open("nieistniejacy.txt")
except Exception as e:
    print(f"Wystąpił błąd: {e}")

# Try-except-else-finally
try:
    liczba = int(input("Liczba: "))
except ValueError:
    print("Błąd!")
else:
    print("Sukces! Kod wykonał się bez błędów")
finally:
    print("Ten kod wykonuje się ZAWSZE")

Debugowanie Kodu

# Technika 1: Wypisywanie (print debugging)
def oblicz_srednia(liczby):
    print(f"DEBUG: liczby = {liczby}")  # Co wchodzi?
    suma = sum(liczby)
    print(f"DEBUG: suma = {suma}")       # Jaki wynik?
    return suma / len(liczby)

# Technika 2: Assercje - sprawdzanie założeń
def podziel(a, b):
    assert b != 0, "Dzielnik nie może być zerem!"
    return a / b

# Technika 3: Używanie debuggera
# W PyCharm/VS Code: postaw breakpoint (czerwona kropka)
# i uruchom w trybie Debug (F5)

# Przydatne funkcje
print(type(zmienna))     # Jaki typ?
print(dir(obiekt))       # Jakie ma metody?
print(help(funkcja))     # Jak działa?

# Cytatu: "Everyone knows that debugging is twice as hard
# as writing a program in the first place." - Brian Kernighan

7. Funkcje i Modularyzacja Kodu

Definiowanie i Wywoływanie Funkcji

# Funkcja bez parametrów
def powitanie():
    print("Witaj w Pythonie!")

powitanie()  # Wywołanie funkcji

# Funkcja z parametrami
def przywitaj_osobe(imie):
    print(f"Witaj, {imie}!")

przywitaj_osobe("Anna")

# Funkcja zwracająca wartość
def dodaj(a, b):
    return a + b

wynik = dodaj(5, 3)  # wynik = 8

# Funkcja z wieloma wartościami zwracanymi
def statystyki(liczby):
    return min(liczby), max(liczby), sum(liczby) / len(liczby)

minimum, maksimum, srednia = statystyki([1, 2, 3, 4, 5])

Argumenty Funkcji - Wymagane i Opcjonalne

# Argumenty wymagane
def przedstaw_sie(imie, nazwisko):
    print(f"Jestem {imie} {nazwisko}")

przedstaw_sie("Jan", "Kowalski")  # Muszę podać oba

# Argumenty opcjonalne (z wartością domyślną)
def powitanie(imie, jezyk="polski"):
    if jezyk == "polski":
        print(f"Cześć, {imie}!")
    elif jezyk == "angielski":
        print(f"Hello, {imie}!")

powitanie("Anna")                    # Użyje "polski"
powitanie("John", "angielski")       # Użyje "angielski"

# Argumenty nazwane (keyword arguments)
def zamow_kawe(rozmiar, rodzaj="espresso", cukier=False):
    print(f"Zamówienie: {rozmiar} {rodzaj}, cukier: {cukier}")

zamow_kawe(rozmiar="duża", cukier=True, rodzaj="latte")

# *args i **kwargs - dowolna liczba argumentów
def suma_wszystkich(*args):
    return sum(args)

print(suma_wszystkich(1, 2, 3, 4, 5))  # 15

Zasięg Zmiennych - Lokalne i Globalne

# Zmienna globalna - widoczna wszędzie
licznik = 0

def zwieksz_licznik():
    global licznik  # Muszę zaznaczyć, że używam globalnej
    licznik += 1

zwieksz_licznik()
print(licznik)  # 1

# Zmienna lokalna - tylko wewnątrz funkcji
def oblicz():
    wynik = 10 + 5  # Lokalna - nie widać na zewnątrz
    return wynik

# print(wynik)  # NameError! wynik nie istnieje tutaj

# Najlepsza praktyka: unikaj zmiennych globalnych!
# Lepiej:
def zwieksz(liczba):
    return liczba + 1

licznik = zwieksz(licznik)

# Cytatu: "Programs must be written for people to read,
# and only incidentally for machines to execute." - Abelson &amp; Sussman

Importowanie Modułów

# Import całego modułu
import math
print(math.pi)        # 3.14159...
print(math.sqrt(16))  # 4.0

# Import konkretnych funkcji
from math import pi, sqrt
print(pi)
print(sqrt(16))

# Import z aliasem (skrót)
import pandas as pd
import numpy as np

# Import własnego modułu
# Plik: moje_funkcje.py
def powitaj():
    return "Cześć!"

# W innym pliku:
# import moje_funkcje
# print(moje_funkcje.powitaj())

# Popularne moduły wbudowane:
# - math: funkcje matematyczne
# - random: liczby losowe
# - datetime: data i czas
# - os: operacje na systemie
# - json: praca z JSON

Dekompozycja Problemu

# Zasada: dziel duże problemy na mniejsze funkcje!

# ŹLE: jedna wielka funkcja
def oblicz_wszystko(dane):
    # 100 linii kodu...
    pass

# DOBRZE: wiele małych funkcji
def wczytaj_dane(plik):
    # Czyta dane z pliku
    return dane

def waliduj_dane(dane):
    # Sprawdza poprawność
    return czy_poprawne

def przetworz_dane(dane):
    # Przetwarza dane
    return wynik

def zapisz_wynik(wynik, plik):
    # Zapisuje do pliku
    pass

# Główna funkcja koordynuje
def main():
    dane = wczytaj_dane("input.txt")
    if waliduj_dane(dane):
        wynik = przetworz_dane(dane)
        zapisz_wynik(wynik, "output.txt")

# Zasada DRY: Don't Repeat Yourself
# Jeśli coś robisz więcej niż raz - zrób z tego funkcję!

Rekurencja - Funkcje Wywołujące Same Siebie

# Rekurencja to technika, gdy funkcja wywołuje samą siebie

# Przykład 1: Silnia (factorial)
def silnia(n):
    """
    Oblicza silnię liczby n (n!)
    5! = 5 * 4 * 3 * 2 * 1 = 120
    """
    # Warunek bazowy (base case) - zatrzymuje rekurencję
    if n == 0 or n == 1:
        return 1
    # Krok rekurencyjny
    return n * silnia(n - 1)

print(silnia(5))  # 120
print(silnia(0))  # 1

# Przykład 2: Ciąg Fibonacciego
def fibonacci(n):
    """
    Zwraca n-tą liczbę Fibonacciego
    0, 1, 1, 2, 3, 5, 8, 13, 21, 34...
    """
    if n &lt;= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

for i in range(10):
    print(fibonacci(i), end=" ")  # 0 1 1 2 3 5 8 13 21 34

# Przykład 3: Suma elementów listy
def suma_rekurencyjna(lista):
    """Sumuje elementy listy rekurencyjnie."""
    if len(lista) == 0:
        return 0
    return lista[0] + suma_rekurencyjna(lista[1:])

print(suma_rekurencyjna([1, 2, 3, 4, 5]))  # 15

Rekurencja vs Iteracja - Praktyczne Zastosowania

# Przykład 4: Odwracanie stringa
def odwroc_string(s):
    """Odwraca string rekurencyjnie."""
    if len(s) <= 1:
        return s
    return s[-1] + odwroc_string(s[:-1])

print(odwroc_string("Python"))  # nohtyP

# Przykład 5: Suma cyfr liczby
def suma_cyfr(n):
    """Sumuje cyfry liczby."""
    if n < 10:
        return n
    return (n % 10) + suma_cyfr(n // 10)

print(suma_cyfr(12345))  # 15 (1+2+3+4+5)

# Przykład 6: Przeszukiwanie struktury katalogów
import os

def znajdz_pliki(sciezka, rozszerzenie):
    """Rekurencyjnie znajduje pliki z danym rozszerzeniem."""
    wyniki = []
    for element in os.listdir(sciezka):
        pelna_sciezka = os.path.join(sciezka, element)
        if os.path.isdir(pelna_sciezka):
            # Rekurencja dla podkatalogów
            wyniki.extend(znajdz_pliki(pelna_sciezka, rozszerzenie))
        elif element.endswith(rozszerzenie):
            wyniki.append(pelna_sciezka)
    return wyniki

# pliki_py = znajdz_pliki(".", ".py")

Optymalizacja Rekurencji i Pułapki

 

ZALETY REKURENCJI:

  • Kod często prostszy i czytelniejszy
  • Naturalny dla problemów o strukturze rekurencyjnej (drzewa, grafy)
  • Matematycznie elegancki

WADY REKURENCJI:

  • Wolniejsza niż iteracja (narzut wywołań funkcji)
  • Zużywa więcej pamięci (stos wywołań)
  • Ryzyko przekroczenia limitu głębokości rekurencji

 

Optymalizacja Rekurencji i Pułapki

 

KIEDY UŻYWAĆ REKURENCJI?

  • Drzewa i grafy (traversal, search)
  • Dziel i zwyciężaj (merge sort, quick sort)
  • Backtracking (sudoku, labirynty)
  • Struktury zagnieżdżone (JSON, XML)

KIEDY UNIKAĆ?

  • Proste pętle (for, while wystarczą)
  • Duże zbiory danych (ryzyko stack overflow)
  • Wydajność krytyczna

Pamiętaj: Każda rekurencja może być zastąpiona iteracją!

 

Funkcje Wyższego Rzędu (Higher-Order Functions)

 

Funkcje wyższego rzędu to funkcje, które:

  • Przyjmują inne funkcje jako argumenty
  • Zwracają funkcje jako wynik
  • Lub jedno i drugie

W Pythonie funkcje są obiektami pierwszej klasy (first-class objects):

  • Można je przypisywać do zmiennych
  • Przekazywać jako argumenty
  • Zwracać z innych funkcji
  • Przechowywać w strukturach danych

 

Funkcje Wyższego Rzędu (Higher-Order Functions)

 

Najważniejsze wbudowane funkcje wyższego rzędu:

  • map() - aplikuje funkcję do każdego elementu
  • filter() - filtruje elementy według warunku
  • reduce() - redukuje sekwencję do pojedynczej wartości
  • sorted() - sortuje z własną funkcją porównania

Zastosowania:

  • Programowanie funkcyjne
  • Przetwarzanie danych
  • Dekoratory
  • Callbacks i event handlers

 

map() i filter() - Transformacja i Filtrowanie

# map() - aplikuje funkcję do każdego elementu

# Tradycyjny sposób
liczby = [1, 2, 3, 4, 5]
kwadraty = []
for n in liczby:
    kwadraty.append(n ** 2)

# Z użyciem map()
def kwadrat(x):
    return x ** 2

kwadraty = list(map(kwadrat, liczby))
print(kwadraty)  # [1, 4, 9, 16, 25]

# Map z lambda
kwadraty = list(map(lambda x: x ** 2, liczby))

# Map na wiele list
a = [1, 2, 3]
b = [10, 20, 30]
sumy = list(map(lambda x, y: x + y, a, b))
print(sumy)  # [11, 22, 33]

# filter() - filtruje elementy według warunku
def jest_parzysta(n):
    return n % 2 == 0

parzyste = list(filter(jest_parzysta, liczby))
print(parzyste)  # [2, 4]

# Filter z lambda
parzyste = list(filter(lambda x: x % 2 == 0, liczby))

# Praktyczny przykład
imiona = ["anna", "piotr", "ewa", "jan", "maria"]
dlugie = list(filter(lambda s: len(s) &gt; 3, imiona))
print(dlugie)  # ['anna', 'piotr', 'maria']

reduce() i sorted() - Redukcja i Sortowanie

from functools import reduce

# reduce() - redukuje sekwencję do pojedynczej wartości
liczby = [1, 2, 3, 4, 5]

# Suma z reduce
def dodaj(a, b):
    return a + b

suma = reduce(dodaj, liczby)
print(suma)  # 15

# Reduce z lambda
suma = reduce(lambda a, b: a + b, liczby)
iloczyn = reduce(lambda a, b: a * b, liczby)
print(iloczyn)  # 120

# Maksimum z reduce
max_wartosc = reduce(lambda a, b: a if a > b else b, liczby)

# sorted() z własną funkcją sortowania
osoby = [
    {"imie": "Anna", "wiek": 25},
    {"imie": "Piotr", "wiek": 30},
    {"imie": "Jan", "wiek": 20}
]

# Sortowanie po wieku
sortowane = sorted(osoby, key=lambda p: p["wiek"])
print([p["imie"] for p in sortowane])  # ['Jan', 'Anna', 'Piotr']

# Sortowanie po imieniu (odwrotnie)
sortowane = sorted(osoby, key=lambda p: p["imie"], reverse=True)

# Sortowanie stringów po długości
slowa = ["python", "js", "java", "c"]
po_dlugosci = sorted(slowa, key=len)
print(po_dlugosci)  # ['c', 'js', 'java', 'python']

Funkcje Zwracające Funkcje - Closures

# Funkcja zwracająca funkcję (closure)

def stworz_mnoznik(n):
    """
    Tworzy funkcję mnożącą przez n.
    Funkcja wewnętrzna 'pamięta' wartość n.
    """
    def mnoznik(x):
        return x * n
    return mnoznik

# Tworzenie specjalizowanych funkcji
razy_2 = stworz_mnoznik(2)
razy_10 = stworz_mnoznik(10)

print(razy_2(5))   # 10
print(razy_10(5))  # 50

# Closure z bardziej złożoną logiką
def stworz_validator(min_len, max_len):
    """Tworzy funkcję walidującą długość stringa."""
    def waliduj(tekst):
        return min_len >= len(tekst) <= max_len
    return waliduj

waliduj_haslo = stworz_validator(8, 20)
waliduj_login = stworz_validator(3, 15)

print(waliduj_haslo("abc"))      # False (za krótkie)
print(waliduj_haslo("bezpieczne123"))  # True
print(waliduj_login("jan"))      # True

# Praktyczny przykład: licznik
def stworz_licznik():
    liczba = 0
    def zwieksz():
        nonlocal liczba  # Modyfikacja zmiennej z outer scope
        liczba += 1
        return liczba
    return zwieksz

licznik1 = stworz_licznik()
licznik2 = stworz_licznik()

print(licznik1())  # 1
print(licznik1())  # 2
print(licznik2())  # 1 (niezależny licznik)

Dekoratory - Modyfikowanie Funkcji

# Dekorator to funkcja wyższego rzędu, która modyfikuje inną funkcję

import time

# Prosty dekorator
def timer(func):
    """Mierzy czas wykonania funkcji."""
    def wrapper(*args, **kwargs):
        start = time.time()
        wynik = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} wykonała się w {end - start:.4f}s")
        return wynik
    return wrapper

# Użycie dekoratora
@timer
def wolna_funkcja():
    time.sleep(1)
    return "Gotowe!"

wynik = wolna_funkcja()
# wolna_funkcja wykonała się w 1.0012s

# Dekorator z logowaniem
def logger(func):
    """Loguje wywołania funkcji."""
    def wrapper(*args, **kwargs):
        print(f"Wywołanie: {func.__name__}({args}, {kwargs})")
        wynik = func(*args, **kwargs)
        print(f"Wynik: {wynik}")
        return wynik
    return wrapper

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

dodaj(3, 5)
# Wywołanie: dodaj((3, 5), {})
# Wynik: 8

Dekoratory z Parametrami i Łańcuchowanie

# Dekorator z parametrami
def powtorz(n):
    """Dekorator powtarzający wykonanie funkcji n razy."""
    def decorator(func):
        def wrapper(*args, **kwargs):
            for i in range(n):
                wynik = func(*args, **kwargs)
            return wynik
        return wrapper
    return decorator

@powtorz(3)
def przywitaj(imie):
    print(f"Cześć, {imie}!")

przywitaj("Anna")
# Cześć, Anna!
# Cześć, Anna!
# Cześć, Anna!

# Łańcuchowanie dekoratorów
def uppercase(func):
    def wrapper(*args, **kwargs):
        wynik = func(*args, **kwargs)
        return wynik.upper()
    return wrapper

def wykrzyknik(func):
    def wrapper(*args, **kwargs):
        wynik = func(*args, **kwargs)
        return wynik + "!"
    return wrapper

@wykrzyknik
@uppercase
def powitanie(imie):
    return f"cześć {imie}"

print(powitanie("anna"))  # CZEŚĆ ANNA!

# Dekoratory są wykonywane od dołu do góry:
# 1. uppercase("cześć anna") → "CZEŚĆ ANNA"
# 2. wykrzyknik("CZEŚĆ ANNA") → "CZEŚĆ ANNA!"

Praktyczne Zastosowania Funkcji Wyższego Rzędu

# Przykład 1: Przetwarzanie danych
studenci = [
    {"imie": "Anna", "oceny": [4, 5, 3, 5]},
    {"imie": "Piotr", "oceny": [3, 3, 4, 3]},
    {"imie": "Jan", "oceny": [5, 5, 5, 4]}
]

# Oblicz średnią dla każdego studenta
srednie = list(map(
    lambda s: {**s, "srednia": sum(s["oceny"]) / len(s["oceny"])},
    studenci
))

# Filtruj studentów ze średnią &gt;= 4
dobrzy = list(filter(lambda s: s["srednia"] &gt;= 4, srednie))

# Przykład 2: Cache dekorator (memoizacja)
from functools import wraps

def cache(func):
    """Cachuje wyniki funkcji."""
    cache_dict = {}

    @wraps(func)
    def wrapper(*args):
        if args not in cache_dict:
            cache_dict[args] = func(*args)
        return cache_dict[args]
    return wrapper

@cache
def fibonacci(n):
    if n &lt;= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(100))  # Bardzo szybko dzięki cache!

# Przykład 3: Walidacja z dekoratorem
def validate_positive(func):
    def wrapper(x):
        if x &lt; 0:
            raise ValueError("Liczba musi być dodatnia!")
        return func(x)
    return wrapper

@validate_positive
def pierwiastek(x):
    return x ** 0.5

print(pierwiastek(16))  # 4.0
# print(pierwiastek(-1))  # ValueError!

8. Praca z Plikami

Czytanie i Zapisywanie Plików Tekstowych

# Zapisywanie do pliku
with open("notatka.txt", "w", encoding="utf-8") as plik:
    plik.write("Witaj, świecie!\n")
    plik.write("To jest druga linia.\n")

# Czytanie całego pliku
with open("notatka.txt", "r", encoding="utf-8") as plik:
    zawartosc = plik.read()
    print(zawartosc)

# Czytanie linijka po linijce
with open("notatka.txt", "r", encoding="utf-8") as plik:
    for linia in plik:
        print(linia.strip())  # strip() usuwa \n

# Tryby otwarcia pliku:
# "r" - odczyt (read)
# "w" - zapis (write) - usuwa poprzednią zawartość!
# "a" - dopisywanie (append)
# "r+" - odczyt i zapis

Praca z Plikami CSV

import csv

# Zapisywanie do CSV
dane = [
    ["Imię", "Nazwisko", "Wiek"],
    ["Jan", "Kowalski", 30],
    ["Anna", "Nowak", 25],
    ["Piotr", "Wiśniewski", 35]
]

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

# Czytanie z CSV
with open("dane.csv", "r", encoding="utf-8") as plik:
    reader = csv.reader(plik)
    for wiersz in reader:
        print(wiersz)

# Czytanie jako słownik (DictReader)
with open("dane.csv", "r", encoding="utf-8") as plik:
    reader = csv.DictReader(plik)
    for wiersz in reader:
        print(f"{wiersz['Imię']} ma {wiersz['Wiek']} lat")

Praca z Formatem JSON

import json

# Słownik Pythona
osoba = {
    "imie": "Jan",
    "nazwisko": "Kowalski",
    "wiek": 30,
    "umiejetnosci": ["Python", "JavaScript", "SQL"]
}

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

# Czytanie z pliku JSON
with open("osoba.json", "r", encoding="utf-8") as plik:
    dane = json.load(plik)
    print(dane["imie"])

# Konwersja do/z stringa JSON
json_string = json.dumps(osoba, indent=2)
z_powrotem = json.loads(json_string)

# JSON to świetny format do przechowywania konfiguracji
# i wymiany danych między aplikacjami!

9. Kodowanie Znaków - ASCII i UTF-8

Czym jest kodowanie znaków?

 

Kodowanie to sposób reprezentowania tekstu jako liczb w pamięci komputera.

ASCII (American Standard Code for Information Interchange):

  • Stary standard (1963)
  • Tylko 128 znaków (0-127)
  • Zawiera: angielskie litery, cyfry, podstawowe znaki
  • NIE obsługuje polskich znaków: ą, ę, ł, ź, ż, ć, ń, ś
  • Zajmuje 1 bajt (8 bitów)

 

9. Kodowanie Znaków - ASCII i UTF-8

Czym jest kodowanie znaków?

UTF-8 (Unicode Transformation Format - 8 bit):

  • Nowoczesny standard
  • Obsługuje ponad 1 milion znaków!
  • Zawiera wszystkie języki świata (polski, chiński, arabski, emoji)
  • Kompatybilny wstecz z ASCII
  • Zajmuje 1-4 bajty (zależnie od znaku)

 

Podstawy Kodowania w Pythonie

# String w Pythonie to Unicode (UTF-8)
tekst = "Witaj, świecie! ąęłźżćńś"

# Zamiana string na bajty (encode)
bajty_utf8 = tekst.encode('utf-8')
print(bajty_utf8)
# b'Witaj, \xc5\x9bwiecie! \xc4\x85\xc4\x99\xc5\x82...'

# Zamiana bajtów na string (decode)
z_powrotem = bajty_utf8.decode('utf-8')
print(z_powrotem)  # Witaj, świecie! ąęłźżćńś

# ASCII - nie obsługuje polskich znaków!
try:
    bajty_ascii = tekst.encode('ascii')
except UnicodeEncodeError as e:
    print(f"Błąd: {e}")
    # Błąd: 'ascii' codec can't encode character '\u015b' in position 6

# Zamiana z ignorowaniem błędów
ascii_ignore = tekst.encode('ascii', errors='ignore')
print(ascii_ignore)  # b'Witaj, wiecie! '

# Zamiana z zastępowaniem znaków
ascii_replace = tekst.encode('ascii', errors='replace')
print(ascii_replace)  # b'Witaj, ?wiecie! ????????'

Konwersja między Kodowaniami

# Usuwanie polskich znaków (transliteracja)
import unicodedata

def usun_polskie_znaki(tekst):
    """
    Zamienia polskie znaki na ich ASCII odpowiedniki.
    ą -&gt; a, ę -&gt; e, ł -&gt; l, etc.
    """
    # Normalizacja NFD rozdziela znaki z akcentami
    nfd = unicodedata.normalize('NFD', tekst)
    # Filtrowanie tylko znaków ASCII
    return ''.join(char for char in nfd
                   if unicodedata.category(char) != 'Mn')

tekst = "Zażółć gęślą jaźń"
ascii_tekst = usun_polskie_znaki(tekst)
print(ascii_tekst)  # Zazolc gesla jazn

# Ręczna mapa transliteracji (lepsze dla polskiego)
POLSKIE_NA_ASCII = {
    'ą': 'a', 'ć': 'c', 'ę': 'e', 'ł': 'l',
    'ń': 'n', 'ó': 'o', 'ś': 's', 'ź': 'z', 'ż': 'z',
    'Ą': 'A', 'Ć': 'C', 'Ę': 'E', 'Ł': 'L',
    'Ń': 'N', 'Ó': 'O', 'Ś': 'S', 'Ź': 'Z', 'Ż': 'Z'
}

def zamien_polskie(tekst):
    for pl, en in POLSKIE_NA_ASCII.items():
        tekst = tekst.replace(pl, en)
    return tekst

print(zamien_polskie("Zażółć gęślą jaźń"))  # Zazolc gesla jazn

Praca z Plikami - Kodowanie

# ZAWSZE określaj kodowanie przy pracy z plikami!

# Zapis z UTF-8 (polskie znaki)
tekst = "Zażółć gęślą jaźń"
with open("polski.txt", "w", encoding="utf-8") as f:
    f.write(tekst)

# Odczyt z UTF-8
with open("polski.txt", "r", encoding="utf-8") as f:
    odczytany = f.read()
    print(odczytany)  # Zażółć gęślą jaźń

# Odczyt z błędnym kodowaniem
try:
    with open("polski.txt", "r", encoding="ascii") as f:
        print(f.read())
except UnicodeDecodeError as e:
    print(f"Błąd dekodowania: {e}")

# Automatyczne wykrywanie kodowania (biblioteka chardet)
# pip install chardet
import chardet

with open("polski.txt", "rb") as f:
    raw_data = f.read()
    result = chardet.detect(raw_data)
    print(f"Wykryte kodowanie: {result['encoding']}")  # utf-8
    print(f"Pewność: {result['confidence']}")          # 0.99

# Odczyt z wykrytym kodowaniem
tekst_decoded = raw_data.decode(result['encoding'])
print(tekst_decoded)

Kody Znaków i Operacje Unicode

# Pobieranie kodu znaku (kod Unicode)
print(ord('A'))      # 65
print(ord('a'))      # 97
print(ord('ą'))      # 261
print(ord('😀'))     # 128512

# Tworzenie znaku z kodu
print(chr(65))       # A
print(chr(97))       # a
print(chr(261))      # ą
print(chr(128512))   # 😀

# Escape sequences dla Unicode
print("\u0105")      # ą (4-cyfrowy hex)
print("\U0001F600")  # 😀 (8-cyfrowy hex)

# Nazwa znaku Unicode
import unicodedata

print(unicodedata.name('ą'))  # LATIN SMALL LETTER A WITH OGONEK
print(unicodedata.name('😀')) # GRINNING FACE

# Lista wszystkich polskich znaków
polskie_znaki = 'ąćęłńóśźżĄĆĘŁŃÓŚŹŻ'
for znak in polskie_znaki:
    print(f"{znak}: {ord(znak)} - {unicodedata.name(znak)}")

# Sprawdzanie kategorii znaku
print(unicodedata.category('A'))   # Lu (Letter, uppercase)
print(unicodedata.category('a'))   # Ll (Letter, lowercase)
print(unicodedata.category('5'))   # Nd (Number, decimal digit)
print(unicodedata.category(' '))   # Zs (Separator, space)

Praktyczne Zastosowania

# 1. Tworzenie przyjaznych URL (slug)
def create_slug(text):
    """Tworzy URL-friendly slug z polskiego tekstu."""
    import re

    # Zamiana na małe litery
    text = text.lower()

    # Usunięcie polskich znaków
    polish_chars = {'ą':'a','ć':'c','ę':'e','ł':'l','ń':'n',
                    'ó':'o','ś':'s','ź':'z','ż':'z'}
    for pl, en in polish_chars.items():
        text = text.replace(pl, en)

    # Zamiana spacji i znaków specjalnych na '-'
    text = re.sub(r'[^a-z0-9]+', '-', text)
    text = text.strip('-')

    return text

print(create_slug("Zażółć gęślą jaźń"))  # zazolc-gesla-jazn
print(create_slug("Python dla Początkujących!"))  # python-dla-poczatkujacych

# 2. Walidacja formularza (tylko ASCII)
def is_ascii_only(text):
    """Sprawdza czy tekst zawiera tylko znaki ASCII."""
    try:
        text.encode('ascii')
        return True
    except UnicodeEncodeError:
        return False

print(is_ascii_only("Hello World"))  # True
print(is_ascii_only("Cześć"))        # False

# 3. Liczenie bajtów vs znaków
tekst = "Zażółć"
print(f"Znaków: {len(tekst)}")                    # 6
print(f"Bajtów UTF-8: {len(tekst.encode('utf-8'))}")  # 11
print(f"Bajtów ASCII: niemożliwe!")

Najczęstsze Problemy i Rozwiązania

 

Problem 1: 'UnicodeDecodeError' przy czytaniu pliku
Rozwiązanie: Użyj encoding='utf-8' lub wykryj kodowanie automatycznie

Problem 2: Polskie znaki wyświetlają się jako '?' lub krzaczki
Rozwiązanie: Upewnij się, że terminal/edytor używa UTF-8

Problem 3: ASCII nie obsługuje emoji i polskich znaków
Rozwiązanie: Zawsze używaj UTF-8 dla międzynarodowego tekstu

Problem 4: Różna długość w bajtach i znakach
Rozwiązanie: len() zwraca znaki, len(text.encode()) zwraca bajty

 

Najczęstsze Problemy i Rozwiązania

 

Dobre praktyki:

  • Zawsze używaj encoding='utf-8' przy open()
  • Przechowuj tekst jako stringi (Unicode), nie bajty
  • Konwertuj na bajty tylko przy zapisie do pliku/sieci
  • Testuj kod z polskimi znakami i emoji
  • Dokumentuj oczekiwane kodowanie w komentarzach

Pamiętaj: Python 3 domyślnie używa Unicode (UTF-8)!

 

10. Wyrażenia Regularne (Regular Expressions)

 

Wyrażenia regularne (regex) to wzorce używane do wyszukiwania i manipulowania tekstem.

Zastosowania:

  • Walidacja danych (email, telefon, kod pocztowy)
  • Wyszukiwanie wzorców w tekście
  • Zamiana i czyszczenie danych
  • Ekstrakcja informacji (URL, daty, numery)
  • Parsowanie logów i plików

 

 

Moduł re w Pythonie:

  • re.search() - szuka pierwszego dopasowania
  • re.match() - sprawdza początek stringa
  • re.findall() - znajduje wszystkie dopasowania
  • re.sub() - zamienia dopasowania
  • re.split() - dzieli string

Podstawowe znaki specjalne:

  • . - dowolny znak (oprócz \n)
  • ^ - początek stringa
  • $ - koniec stringa
  • * - 0 lub więcej powtórzeń
  • + - 1 lub więcej powtórzeń
  • ? - 0 lub 1 wystąpienie
  • [] - zestaw znaków
  • () - grupa
  • | - lub (alternatywa)

 

 

Podstawy Regex - Pierwsze Kroki

import re

# Podstawowe wyszukiwanie
tekst = "Python jest super! Python to świetny język."

# search() - znajduje pierwsze dopasowanie
wynik = re.search(r"Python", tekst)
if wynik:
    print("Znaleziono:", wynik.group())  # Python
    print("Pozycja:", wynik.start())     # 0

# findall() - znajduje wszystkie dopasowania
wszystkie = re.findall(r"Python", tekst)
print(wszystkie)  # ['Python', 'Python']

# match() - sprawdza początek stringa
if re.match(r"Python", tekst):
    print("String zaczyna się od 'Python'")

# split() - dzieli string wzorcem
zdania = re.split(r"[.!?]", tekst)
print(zdania)  # ['Python jest super', ' Python to świetny język', '']

# sub() - zamienia wzorzec
nowy = re.sub(r"Python", "Java", tekst)
print(nowy)  # Java jest super! Java to świetny język.

Wzorce i Klasy Znaków

import re

# Klasy znaków
tekst = "Rok 2024, tel: 123-456-789, email: jan@example.com"

# \d - cyfra (digit), \D - nie-cyfra
cyfry = re.findall(r"\d+", tekst)
print(cyfry)  # ['2024', '123', '456', '789']

# \w - znak słowa (litera, cyfra, _), \W - nie-znak-słowa
slowa = re.findall(r"\w+", tekst)
print(slowa)  # ['Rok', '2024', 'tel', '123', '456', '789', 'email', 'jan', 'example', 'com']

# \s - biały znak (spacja, tab, \n), \S - nie-biały-znak
bez_spacji = re.findall(r"\S+", tekst)
print(bez_spacji)

# [] - własny zestaw znaków
samogloski = re.findall(r"[aeiouąę]", tekst.lower())
print(samogloski)

# [^] - negacja zestwu
nie_cyfry = re.findall(r"[^0-9]+", tekst)
print(nie_cyfry)

# . - dowolny znak
wzor = re.findall(r"t.l", tekst)  # tel
print(wzor)

Kwantyfikatory - Ilość Powtórzeń

import re

# Kwantyfikatory określają ilość powtórzeń

# * - 0 lub więcej
print(re.findall(r"ab*", "a ab abb abbb"))  # ['a', 'ab', 'abb', 'abbb']

# + - 1 lub więcej
print(re.findall(r"ab+", "a ab abb abbb"))  # ['ab', 'abb', 'abbb']

# ? - 0 lub 1 (opcjonalny)
print(re.findall(r"colou?r", "color colour"))  # ['color', 'colour']

# {n} - dokładnie n razy
print(re.findall(r"\d{4}", "2024 123 56789"))  # ['2024', '5678']

# {n,m} - od n do m razy
print(re.findall(r"\d{2,4}", "1 12 123 1234 12345"))
# ['12', '123', '1234', '1234']

# {n,} - n lub więcej razy
print(re.findall(r"a{2,}", "a aa aaa aaaa"))  # ['aa', 'aaa', 'aaaa']

# Zachłanne vs lenliwe
tekst = "<div>Hello</div><div>World</div>"
zachlanne = re.findall(r"<div>.*</div>", tekst)
print(zachlanne)  # ['<div>Hello</div><div>World</div>']

lenliwe = re.findall(r"<div>.*?</div>", tekst)
print(lenliwe)  # ['<div>Hello</div>', '<div>World</div>']

Grupy i Przechwytywanie

import re

# () - grupy przechwytujące
tekst = "Jan Kowalski, email: jan@example.com, tel: 123-456-789"

# Pojedyncza grupa
wynik = re.search(r"email: (\S+)", tekst)
if wynik:
    print(wynik.group(0))  # email: jan@example.com (cały match)
    print(wynik.group(1))  # jan@example.com (grupa 1)

# Wiele grup
wzor = r"(\w+)@(\w+)\.(\w+)"
email = re.search(wzor, tekst)
if email:
    print(email.group(0))  # jan@example.com
    print(email.group(1))  # jan
    print(email.group(2))  # example
    print(email.group(3))  # com

# Nazwane grupy (?P)
wzor = r"(?P\w+)@(?P\w+\.\w+)"
match = re.search(wzor, tekst)
if match:
    print(match.group('user'))    # jan
    print(match.group('domain'))  # example.com

# Grupy nieprzechwytujące (?:)
wzor = r"(?:Mr|Mrs|Ms)\.? (\w+)"
tekst2 = "Mr. Smith and Mrs. Johnson"
print(re.findall(wzor, tekst2))  # ['Smith', 'Johnson']

Walidacja Danych - Praktyczne Wzorce

import re

# Walidacja email
def waliduj_email(email):
    wzor = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
    return bool(re.match(wzor, email))

print(waliduj_email("jan@example.com"))      # True
print(waliduj_email("niepoprawny.email"))    # False

# Walidacja numeru telefonu (format: XXX-XXX-XXX)
def waliduj_telefon(tel):
    wzor = r"^\d{3}-\d{3}-\d{3}$"
    return bool(re.match(wzor, tel))

print(waliduj_telefon("123-456-789"))  # True
print(waliduj_telefon("12-345-6789"))  # False

# Walidacja kodu pocztowego (XX-XXX)
def waliduj_kod_pocztowy(kod):
    wzor = r"^\d{2}-\d{3}$"
    return bool(re.match(wzor, kod))

print(waliduj_kod_pocztowy("00-950"))  # True
print(waliduj_kod_pocztowy("1234"))    # False

# Walidacja hasła (min 8 znaków, litera i cyfra)
def waliduj_haslo(haslo):
    if len(haslo) &lt; 8:
        return False
    ma_litere = bool(re.search(r"[a-zA-Z]", haslo))
    ma_cyfre = bool(re.search(r"\d", haslo))
    return ma_litere and ma_cyfre

print(waliduj_haslo("Haslo123"))  # True
print(waliduj_haslo("haslo"))     # False

Ekstrakcja Danych z Tekstu

import re

tekst = """
Kontakt:
Jan Kowalski - jan@example.com - 123-456-789
Anna Nowak - anna.nowak@test.pl - 987-654-321
Strona: https://example.com
Cena: 1299.99 PLN
Data: 2024-10-26
"""

# Ekstrakcja adresów email
emails = re.findall(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}", tekst)
print("Emaile:", emails)

# Ekstrakcja numerów telefonów
telefony = re.findall(r"\d{3}-\d{3}-\d{3}", tekst)
print("Telefony:", telefony)

# Ekstrakcja URL
urls = re.findall(r"https?://[^\s]+", tekst)
print("URL:", urls)

# Ekstrakcja cen (liczby zmiennoprzecinkowe)
ceny = re.findall(r"\d+\.\d{2}", tekst)
print("Ceny:", ceny)

# Ekstrakcja dat (format YYYY-MM-DD)
daty = re.findall(r"\d{4}-\d{2}-\d{2}", tekst)
print("Daty:", daty)

# Ekstrakcja imion i nazwisk z emailami
wzor = r"(\w+ \w+) - ([\w.]+@[\w.]+)"
osoby = re.findall(wzor, tekst)
for imie_nazwisko, email in osoby:
    print(f"{imie_nazwisko}: {email}")

Zaawansowane Techniki i Flagi

import re

# Flagi modyfikujące zachowanie regex

# re.IGNORECASE (re.I) - ignoruje wielkość liter
tekst = "Python python PYTHON"
print(re.findall(r"python", tekst, re.IGNORECASE))
# ['Python', 'python', 'PYTHON']

# re.MULTILINE (re.M) - ^ i $ dla każdej linii
tekst_wieloliniowy = """pierwsza linia
druga linia
trzecia linia"""
print(re.findall(r"^\w+", tekst_wieloliniowy, re.MULTILINE))
# ['pierwsza', 'druga', 'trzecia']

# re.DOTALL (re.S) - . dopasowuje też \n
html = "<div>\nHello\n</div>"
print(re.findall(r"<div>.*</div>", html, re.DOTALL))
# ['<div>\nHello\n</div>']

# Lookahead i Lookbehind
tekst = "Price: 100 USD, 200 EUR, 300 PLN"

# Positive lookahead (?=)
usd = re.findall(r"\d+(?= USD)", tekst)
print(usd)  # ['100']

# Negative lookahead (?!)
nie_usd = re.findall(r"\d+(?! USD)", tekst)
print(nie_usd)  # ['0', '200', '300']

# Positive lookbehind (?&lt;=)
po_price = re.findall(r"(?&lt;=Price: )\d+", tekst)
print(po_price)  # ['100']

Praktyczne Zastosowania i Wskazówki

 

PRAKTYCZNE PRZYKŁADY:

  1. Czyszczenie danych
    • Usuwanie zbędnych spacji: re.sub(r'\s+', ' ', tekst)
    • Usuwanie znaków specjalnych: re.sub(r'[^a-zA-Z0-9]', '', tekst)
  2. Maskowanie danych wrażliwych
    • Maskowanie numeru karty: re.sub(r'\d{4}', '****', numer)
    • Ukrywanie części email: re.sub(r'(\w{2})\w+@', r'\1***@', email)
  3. Parsowanie logów
    • Ekstrakcja IP: r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
    • Znaczniki czasu: r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}'

 

Praktyczne Zastosowania i Wskazówki

 

WSKAZÓWKI:

  • Używaj r'' (raw strings) dla wzorców regex
  • Kompiluj często używane wzorce: pattern = re.compile(r'...')
  • Testuj regex online: regex101.com, regexr.com
  • Unikaj nadmiernej zachłanności - używaj ? gdy potrzeba
  • Grupuj dla czytelności: (?P<nazwa>wzor)

CZĘSTE BŁĘDY:

  • Zapominanie o escape'owaniu znaków specjalnych: \., \?, \+
  • Użycie . zamiast \. dla kropki literalnej
  • Zachłanne dopasowania gdy potrzeba leniwe (.*? zamiast .*)
  • Brak ^ i $ przy walidacji (pozwala na częściowe dopasowania)

Pamiętaj: Regex to potężne narzędzie, ale nie nadużywaj go! Dla prostych operacji użyj str.find(), str.replace(), str.split()

 

11. Programowanie Obiektowe (OOP)

Klasy i Obiekty - Wprowadzenie

# Definicja klasy
class Samochod:
    def __init__(self, marka, model, rok):
        self.marka = marka      # Atrybut
        self.model = model
        self.rok = rok
        self.przebieg = 0

    # Metoda
    def jedz(self, kilometry):
        self.przebieg += kilometry
        print(f"Pojechałeś {kilometry} km")

    def informacje(self):
        return f"{self.marka} {self.model} ({self.rok}), przebieg: {self.przebieg} km"

# Tworzenie obiektów (instancji)
auto1 = Samochod("Toyota", "Corolla", 2020)
auto2 = Samochod("BMW", "X5", 2022)

# Wywoływanie metod
auto1.jedz(150)
print(auto1.informacje())  # Toyota Corolla (2020), przebieg: 150 km

Atrybuty Klasy vs Instancji

class Produkt:
    # Atrybut klasy - wspólny dla wszystkich obiektów
    vat = 0.23
    licznik_produktow = 0

    def __init__(self, nazwa, cena_netto):
        # Atrybuty instancji - unikalne dla każdego obiektu
        self.nazwa = nazwa
        self.cena_netto = cena_netto
        Produkt.licznik_produktow += 1

    def cena_brutto(self):
        return self.cena_netto * (1 + Produkt.vat)

    @classmethod
    def zmien_vat(cls, nowy_vat):
        cls.vat = nowy_vat

    @staticmethod
    def czy_drogie(cena):
        return cena &gt; 1000

# Użycie
laptop = Produkt("Laptop", 3000)
mysz = Produkt("Mysz", 50)

print(laptop.cena_brutto())          # 3690.0
print(Produkt.licznik_produktow)     # 2
Produkt.zmien_vat(0.08)              # Zmienia VAT dla wszystkich
print(Produkt.czy_drogie(1500))      # True

Dziedziczenie - Rozszerzanie Klas

# Klasa bazowa (rodzic)
class Zwierze:
    def __init__(self, imie):
        self.imie = imie

    def wydaj_dzwiek(self):
        return "..."

    def przedstaw_sie(self):
        return f"Jestem {self.imie}, mówię: {self.wydaj_dzwiek()}"

# Klasy pochodne (dzieci) dziedziczą po Zwierze
class Pies(Zwierze):
    def wydaj_dzwiek(self):
        return "Hau hau!"

    def aportuj(self):
        return f"{self.imie} aportuje piłkę"

class Kot(Zwierze):
    def wydaj_dzwiek(self):
        return "Miau!"

# Użycie
burek = Pies("Burek")
filemon = Kot("Filemon")

print(burek.przedstaw_sie())  # Jestem Burek, mówię: Hau hau!
print(filemon.przedstaw_sie()) # Jestem Filemon, mówię: Miau!
print(burek.aportuj())         # Burek aportuje piłkę

Enkapsulacja i Metody Specjalne

class KontoBankowe:
    def __init__(self, wlasciciel, saldo=0):
        self.wlasciciel = wlasciciel
        self.__saldo = saldo  # __ oznacza atrybut prywatny

    def wplata(self, kwota):
        if kwota &gt; 0:
            self.__saldo += kwota
            return True
        return False

    def wyplata(self, kwota):
        if 0 &lt; kwota &lt;= self.__saldo:
            self.__saldo -= kwota
            return True
        return False

    def sprawdz_saldo(self):
        return self.__saldo

    # Metody specjalne (dunder methods)
    def __str__(self):
        return f"Konto: {self.wlasciciel}, saldo: {self.__saldo} PLN"

    def __repr__(self):
        return f"KontoBankowe('{self.wlasciciel}', {self.__saldo})"

konto = KontoBankowe("Jan Kowalski", 1000)
konto.wplata(500)
print(konto)  # Konto: Jan Kowalski, saldo: 1500 PLN
# print(konto.__saldo)  # AttributeError - atrybut prywatny!

12. List Comprehensions i Wyrażenia Generatorowe

List Comprehensions - Eleganckie Tworzenie List

# Tradycyjny sposób
kwadraty = []
for i in range(10):
    kwadraty.append(i ** 2)

# List comprehension - krótsza wersja!
kwadraty = [i ** 2 for i in range(10)]
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# Z warunkiem (filtrowanie)
parzyste = [i for i in range(20) if i % 2 == 0]
# [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

# Operacje na stringach
owoce = ["jabłko", "banan", "gruszka"]
wielkie = [owoc.upper() for owoc in owoce]
# ['JABŁKO', 'BANAN', 'GRUSZKA']

# Z if-else
liczby = [1, 2, 3, 4, 5]
kategorie = ["parzysta" if n % 2 == 0 else "nieparzysta" for n in liczby]

# Zagnieżdżone comprehensions (2D)
macierz = [[i * j for j in range(3)] for i in range(3)]
# [[0, 0, 0], [0, 1, 2], [0, 2, 4]]

Dictionary i Set Comprehensions

# Dictionary comprehension
kwadraty_dict = {i: i**2 for i in range(6)}
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# Z dwóch list
imiona = ["Anna", "Jan", "Piotr"]
wieki = [25, 30, 35]
osoby = {imie: wiek for imie, wiek in zip(imiona, wieki)}
# {'Anna': 25, 'Jan': 30, 'Piotr': 35}

# Zamiana kluczy i wartości
odwrocone = {v: k for k, v in osoby.items()}
# {25: 'Anna', 30: 'Jan', 35: 'Piotr'}

# Set comprehension
liczby = [1, 2, 2, 3, 3, 3, 4, 5]
unikalne_kwadraty = {x**2 for x in liczby}
# {1, 4, 9, 16, 25}

# Praktyczny przykład: filtrowanie słownika
produkty = {"jabłko": 2.5, "banan": 3.0, "gruszka": 4.5}
drogie = {k: v for k, v in produkty.items() if v &gt; 3}
# {'banan': 3.0, 'gruszka': 4.5}

Generator Expressions - Wydajność Pamięci

# List comprehension - tworzy całą listę w pamięci
lista = [i**2 for i in range(1000000)]  # Zajmuje dużo pamięci!

# Generator expression - generuje elementy na żądanie
generator = (i**2 for i in range(1000000))  # Prawie nie zajmuje pamięci!

# Użycie generatora
for kwadrat in generator:
    if kwadrat &gt; 100:
        break

# Generatory są jednorazowe!
suma = sum(i**2 for i in range(100))  # Generator jako argument

# Praktyczny przykład: czytanie dużych plików
# ŹLE: czyta cały plik do pamięci
with open("duzy_plik.txt") as f:
    linie = [linia.strip() for linia in f]

# DOBRZE: przetwarza linijka po linijce
with open("duzy_plik.txt") as f:
    for linia in (l.strip() for l in f):
        # Przetwarzaj linię
        pass

# Kiedy używać generatorów?
# - Duże zbiory danych
# - Nie potrzebujesz całej listy od razu
# - Oszczędzasz pamięć

13. Popularne Biblioteki Standardowe

Moduł datetime - Praca z Datą i Czasem

from datetime import datetime, date, time, timedelta

# Aktualna data i czas
teraz = datetime.now()
print(teraz)  # 2024-10-26 14:30:45.123456

# Tworzenie własnych dat
data_urodzenia = date(1990, 5, 15)
godzina = time(14, 30, 0)

# Formatowanie dat
dzis = date.today()
print(dzis.strftime("%d/%m/%Y"))      # 26/10/2024
print(dzis.strftime("%A, %d %B %Y"))  # Sobota, 26 październik 2024

# Parsowanie stringów na daty
data_str = "2024-10-26"
data = datetime.strptime(data_str, "%Y-%m-%d")

# Operacje na datach
za_tydzien = dzis + timedelta(days=7)
wczoraj = dzis - timedelta(days=1)
za_2_godziny = datetime.now() + timedelta(hours=2)

# Obliczanie wieku
wiek = dzis.year - data_urodzenia.year

Moduł random - Liczby Losowe

import random

# Losowa liczba zmiennoprzecinkowa z zakresu [0.0, 1.0)
losowa = random.random()

# Losowa liczba całkowita
kostka = random.randint(1, 6)           # Rzut kostką
los = random.randrange(0, 100, 5)       # Co 5: 0, 5, 10, ..., 95

# Losowy wybór z listy
kolory = ["czerwony", "niebieski", "zielony", "żółty"]
wybrany = random.choice(kolory)

# Losowe próbkowanie (bez powtórzeń)
losowe_3 = random.sample(kolory, 3)

# Tasowanie listy
karty = list(range(1, 53))
random.shuffle(karty)  # Zmienia listę w miejscu

# Losowa liczba z rozkładu normalnego
wzrost = random.gauss(170, 10)  # średnia=170, odch.std=10

# Ustawianie ziarna (seed) dla powtarzalności
random.seed(42)
print(random.randint(1, 100))  # Zawsze ten sam wynik!

Moduły os i pathlib - Operacje Systemowe

import os
from pathlib import Path

# Aktualna ścieżka
obecny_katalog = os.getcwd()
print(obecny_katalog)

# Tworzenie katalogów
os.makedirs("projekty/python/skrypty", exist_ok=True)

# Listowanie plików
pliki = os.listdir(".")
for plik in pliki:
    print(plik)

# Sprawdzanie istnienia
if os.path.exists("plik.txt"):
    print("Plik istnieje!")

# pathlib - nowoczesny sposób (Python 3.4+)
sciezka = Path("projekty/python/skrypty")
sciezka.mkdir(parents=True, exist_ok=True)

# Operacje na ścieżkach
plik = Path("dane/input.txt")
print(plik.name)        # input.txt
print(plik.stem)        # input
print(plik.suffix)      # .txt
print(plik.parent)      # dane

# Iteracja przez pliki
for plik in Path(".").glob("*.py"):
    print(f"Znaleziono: {plik}")

14. Praktyczne Projekty - Zastosowanie Wiedzy

import random
import string

def generuj_haslo(dlugosc=12, wielkie=True, cyfry=True, znaki=True):
    """
    Generuje losowe hasło o zadanej długości.
    """
    znaki_do_wyboru = string.ascii_lowercase

    if wielkie:
        znaki_do_wyboru += string.ascii_uppercase
    if cyfry:
        znaki_do_wyboru += string.digits
    if znaki:
        znaki_do_wyboru += "!@#$%^&amp;*"

    haslo = ''.join(random.choice(znaki_do_wyboru) for _ in range(dlugosc))
    return haslo

# Użycie
for _ in range(3):
    print(generuj_haslo(16))

# Przykładowe hasła:
# aB7$mK2@pL9#qR5!
# x3Y&amp;nZ8*wV1%tU6@
# dF4!gH9#jK2$mN7&amp;

Projekt 2: Lista Zadań (To-Do List)

class ListaZadan:
    def __init__(self):
        self.zadania = []

    def dodaj(self, zadanie):
        self.zadania.append({"tekst": zadanie, "wykonane": False})
        print(f"✓ Dodano: {zadanie}")

    def pokaz(self):
        if not self.zadania:
            print("Lista zadań jest pusta!")
            return

        for i, zadanie in enumerate(self.zadania, 1):
            status = "✓" if zadanie["wykonane"] else "○"
            print(f"{i}. [{status}] {zadanie['tekst']}")

    def wykonaj(self, numer):
        if 1 &lt;= numer &lt;= len(self.zadania):
            self.zadania[numer-1]["wykonane"] = True
            print(f"✓ Wykonano zadanie {numer}")

    def usun(self, numer):
        if 1 &lt;= numer &lt;= len(self.zadania):
            zadanie = self.zadania.pop(numer-1)
            print(f"Usunięto: {zadanie['tekst']}")

# Użycie
todo = ListaZadan()
todo.dodaj("Nauczyć się Pythona")
todo.dodaj("Zrobić projekt")
todo.pokaz()
todo.wykonaj(1)

Projekt 3: Analiza Pliku Tekstowego

def analizuj_tekst(sciezka_pliku):
    """
    Analizuje plik tekstowy i zwraca statystyki.
    """
    with open(sciezka_pliku, 'r', encoding='utf-8') as plik:
        tekst = plik.read()

    # Podstawowe statystyki
    liczba_znakow = len(tekst)
    liczba_slow = len(tekst.split())
    liczba_linii = tekst.count('\n') + 1

    # Najczęstsze słowa
    slowa = tekst.lower().split()
    from collections import Counter
    najczestsze = Counter(slowa).most_common(5)

    # Wyniki
    print(f"Analiza pliku: {sciezka_pliku}")
    print(f"Znaków: {liczba_znakow:,}")
    print(f"Słów: {liczba_slow:,}")
    print(f"Linii: {liczba_linii:,}")
    print(f"\nNajczęstsze słowa:")
    for slowo, ilosc in najczestsze:
        print(f"  '{slowo}': {ilosc} razy")

# Użycie
analizuj_tekst("przyklad.txt")

Projekt 4: Kalkulator BMI z Klasami

class Osoba:
    def __init__(self, imie, waga_kg, wzrost_m):
        self.imie = imie
        self.waga = waga_kg
        self.wzrost = wzrost_m

    def oblicz_bmi(self):
        return self.waga / (self.wzrost ** 2)

    def kategoria_bmi(self):
        bmi = self.oblicz_bmi()
        if bmi &lt; 18.5:
            return "niedowaga"
        elif bmi &lt; 25:
            return "waga prawidłowa"
        elif bmi &lt; 30:
            return "nadwaga"
        else:
            return "otyłość"

    def raport(self):
        bmi = self.oblicz_bmi()
        kategoria = self.kategoria_bmi()
        return f"""
        Raport BMI dla: {self.imie}
        Waga: {self.waga} kg
        Wzrost: {self.wzrost} m
        BMI: {bmi:.2f}
        Kategoria: {kategoria}
        """

# Użycie
osoba = Osoba("Jan Kowalski", 75, 1.80)
print(osoba.raport())

Ćwiczenia Praktyczne - Co Dalej?

Pomysły na własne projekty: 1. Gra w "Zgadnij liczbę" - Użyj random.randint() - Pętle while i input() - Warunki if/elif/else 2. Konwerter jednostek - Funkcje do konwersji (km↔mile, kg↔funty) - Słownik z przelicznikami - Obsługa błędów try/except 3. Dziennik wydatków - Zapisywanie do pliku CSV - Sumowanie kategorii - Analiza miesięczna 4. Quiz wiedzy - Lista słowników z pytaniami - Losowa kolejność pytań - Licznik punktów 5. Prosty sklep internetowy - Klasy: Produkt, Koszyk - Metody: dodaj_do_koszyka, oblicz_total - Zapis zamówienia do JSON Pamiętaj: najlepiej uczyć się przez praktykę! 🚀

Podsumowanie

Czego się nauczyliśmy:

✓ Przygotowanie środowiska Pythona ✓ Zmienne, typy danych i operacje ✓ Struktury kontrolne (if, for, while) ✓ Kolekcje danych (listy, słowniki, zbiory, krotki) ✓ Unpacking - rozpakowywanie (*args, **kwargs) ✓ Obsługa błędów i debugowanie ✓ Funkcje: modularyzacja, rekurencja, HOF, dekoratory ✓ Praca z plikami (TXT, CSV, JSON) ✓ Kodowanie znaków (ASCII, UTF-8, Unicode) ✓ Wyrażenia regularne (regex, walidacja, ekstrakcja) ✓ Programowanie obiektowe (klasy, dziedziczenie) ✓ List comprehensions i generatory ✓ Popularne biblioteki (datetime, random, os/pathlib) ✓ Praktyczne projekty i ćwiczenia "The best way to learn Python is to use Python!" - Community Wisdom Dziękuję za uwagę! Czas na praktykę! 🐍

Python - SWPS

By noinputsignal

Python - SWPS

  • 73