Odcinek 10/15 – Zaawansowane struktury i techniki funkcyjne

foto kurs pythona odcinek 10

Cel: po tym rozdziale Twój kod będzie krótszy, szybszy i bardziej „pythonowy”.
Poznasz:

  • comprehensions (czyli skrócony zapis pętli),
  • iteratory i generatory,
  • funkcje map, filter, reduce,
  • lambda (funkcje anonimowe),
  • dekoratory (modyfikowanie funkcji w locie).

1) Comprehensions – pętle w jednej linijce

To prosty zapis, który tworzy listy, słowniki i zbiory bez długich pętli.

Lista

# zwykła pętla
squares = []
for n in range(10):
    squares.append(n * n)

# krócej:
squares = [n * n for n in range(10)]

Z warunkiem:

even = [n for n in range(10) if n % 2 == 0]
print(even)  # [0, 2, 4, 6, 8]

Słownik

names = ["Ala", "Ola", "Ela"]
lengths = {n: len(n) for n in names}
print(lengths)  # {'Ala': 3, 'Ola': 3, 'Ela': 3}

Zbiór

unique = {c.lower() for c in "PythonPYTHON"}
print(unique)  # {'p', 'y', 't', 'h', 'o', 'n'}

💡 Używaj comprehensions, gdy tworzysz nową kolekcję z innej.
Jeśli logika jest zbyt skomplikowana – lepsza zwykła pętla.


2) Iteratory – obiekty „po których się chodzi”

Iterator to „pilot” do przechodzenia po danych.
Każdy iterator ma metody __iter__() i __next__().

nums = [1, 2, 3]
it = iter(nums)
print(next(it))  # 1
print(next(it))  # 2

Pętla for sama w tle korzysta z iteratorów.


3) Generatory – dane „na żądanie”

Generator to specjalny iterator, który nie trzyma wszystkiego w pamięci, tylko daje kolejne elementy w miarę potrzeby.

def licz_od_do(a, b):
    while a <= b:
        yield a
        a += 1

for n in licz_od_do(3, 6):
    print(n)  # 3, 4, 5, 6

Można też zrobić generator w jednej linijce:

suma = sum(n * n for n in range(1_000_000))
print(suma)

4) Funkcje wyższego rzędu – map, filter, reduce

map – przekształca każdy element:

nums = [1, 2, 3]
doubled = list(map(lambda x: x * 2, nums))
print(doubled)  # [2, 4, 6]

filter – zostawia elementy spełniające warunek:

even = list(filter(lambda x: x % 2 == 0, nums))
print(even)  # [2]

reduce – redukuje całą listę do jednej wartości (trzeba functools):

from functools import reduce
product = reduce(lambda a, b: a * b, nums)
print(product)  # 6

5) Funkcje anonimowe – lambda

lambda to krótka funkcja w jednej linijce.

kwadrat = lambda x: x**2
print(kwadrat(5))  # 25

Praktyczne użycie:

names = ["ela", "ola", "Ala"]
print(sorted(names, key=lambda n: n.lower()))
# ['Ala', 'ela', 'ola']

6) Dekoratory – funkcje, które ulepszają inne funkcje

Dekorator przyjmuje funkcję, a zwraca nową, np. z dodatkowymi logami.

def log(func):
    def wrapper(*args, **kwargs):
        print("Wywołuję:", func.__name__)
        result = func(*args, **kwargs)
        print("Wynik:", result)
        return result
    return wrapper

@log
def add(a, b):
    return a + b

add(3, 4)

Przydatne np. do mierzenia czasu działania, logowania, sprawdzania uprawnień.


7) Mini-projekty (spróbuj sam)

A) Generator haseł – comprehension + random

import random, string
password = "".join(random.choice(string.ascii_letters) for _ in range(12))
print(password)

B) Analiza tekstu – dict comprehension

txt = "Ala ma kota a kot ma Ale"
counts = {w: txt.split().count(w) for w in set(txt.split())}
print(counts)

C) Pomiar czasu działania – dekorator

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"Czas: {end - start:.5f}s")
        return result
    return wrapper

@timer
def slow():
    time.sleep(1)
    return "gotowe"

print(slow())

8) Typowe pułapki i jak ich uniknąć

ProblemCo się dziejeRada
Zbyt skomplikowany comprehensionkod trudny do czytaniapodziel na kilka prostych pętli
Nadużywanie lambdatrudniej debugowaćdla większej logiki zrób normalną funkcję
Generator użyty drugi razdaje puste wynikitwórz nowy generator przy każdym użyciu
Brak functools.wraps w dekoratorzetracisz nazwę i opis funkcjiużyj from functools import wraps i dodaj @wraps(func)

9) Zadania do samodzielnego zrobienia

  1. Zbuduj list comprehension, który zwróci kwadraty liczb parzystych od 0 do 20.
  2. Napisz generator liczb Fibonacciego.
  3. Użyj map i filter, aby z listy słów wybrać te na „a” i zamienić na wielkie litery.
  4. Stwórz dekorator, który mierzy czas działania dowolnej funkcji i wypisuje wynik.
  5. Użyj reduce, aby obliczyć największy wspólny dzielnik (NWD) listy liczb.

Co zabierasz z odcinka 10?

  • Tworzysz list/dict/set comprehensions.
  • Wiesz, jak działają iteratory i generatory.
  • Używasz map, filter, reduce i lambda.
  • Potrafisz pisać dekoratory do logowania czy pomiaru czasu.
  • Twój kod staje się krótszy, szybszy i czytelniejszy.