Przegląd

Zebrane poniżej notatki to skrócona ściągawka przygotowująca do rozmów technicznych o Pythonie. Materiał został pogrupowany tak, aby najpierw uporządkować kluczowe pytania rekrutacyjne, następnie odświeżyć nowości w Pythonie 3.14, przypomnieć fundamenty języka oraz zanurzyć się w tematach związanych z równoległością i architekturą CPythona.


Interview Essentials

1. Główne cechy języka Python

Python to interpretowany, wysokopoziomowy język ogólnego przeznaczenia, który stawia na czytelność i produktywność.

  • Dynamiczne typowanie — typy wartości ustalane są w czasie wykonania.
  • Interpretowany — brak konieczności kompilacji do kodu maszynowego.
  • Garbage Collector — automatyczne zarządzanie pamięcią i odzyskiwanie nieużywanych obiektów.
  • Czysta obiektowość — w Pythonie wszystko jest obiektem, łącznie z funkcjami i klasami.
  • Rozszerzalność — łatwa integracja z modułami w C/C++ i bogaty ekosystem bibliotek.
  • Wieloparadygmatowość — programowanie imperatywne, funkcyjne, obiektowe oraz asynchroniczne.
  • Pythonic style — nacisk na czytelność, idiomy i wytyczne PEP 8.

Na rozmowie warto dodać:

„Python pozwala pisać bardzo ekspresyjny, ale czytelny kod, łącząc elastyczność dynamicznego typowania z automatycznym zarządzaniem pamięcią.”


2. Zarządzanie pamięcią

Python korzysta z prywatnej sterty zarządzanej przez interpreter. Dwa filary zarządzania pamięcią to:

  • Licznik referencji — każdy obiekt przechowuje liczbę odniesień; kiedy spada do zera, obiekt jest zwalniany.
  • Garbage Collector — moduł gc wykrywa i usuwa cykle referencji.
import gc
gc.collect()

Warto pamiętać: Interpreter może ponownie używać zarezerwowanych bloków pamięci, więc zwolnienie obiektu nie oznacza natychmiastowego oddania pamięci systemowi.

Na rozmowie:

„Python łączy licznik referencji z garbage collectorem do cykli, dlatego zwykle unikamy wycieków pamięci, ale musimy uważać na zamknięte referencje w zagnieżdżonych strukturach.”


3. Obsługa wyjątków

Python stosuje mechanizm try / except / else / finally, realizujący propagację wyjątków (stack unwinding).

try:
    result = 10 / 0
except ZeroDivisionError as err:
    print(f"Błąd: {err}")
else:
    print("Brak błędów")
finally:
    print("Zawsze się wykona")

Tworzenie własnych wyjątków:

class InvalidInputError(Exception):
    """Custom domain-specific exception."""
    pass

Na rozmowie:

„Wyjątki w Pythonie propagują się po stosie do momentu przechwycenia, co pozwala oddzielić logikę błędów od logiki biznesowej.”


4. Lista vs krotka

CechaLista (list)Krotka (tuple)
Mutowalność
Typowy zapis[1, 2, 3](1, 2, 3)
WydajnośćWolniejsza (dynamiczna)Szybsza (niemutowalna)
ZastosowanieZmienne kolekcjeStałe zestawy wartości
Klucz w słowniku✅ (jeśli elementy hashable)

Pułapka: Krotka z jednym elementem wymaga przecinka: x = (5,).

Na rozmowie:

„Krotki, dzięki niemutowalności, mogą być kluczami w słownikach i elementami zbiorów. Listy są elastyczne, ale nie nadają się na klucze hashujące.”


5. Dziedziczenie i MRO

Python obsługuje dziedziczenie pojedyncze i wielokrotne. Kolejność wyszukiwania metod definiuje MRO (Method Resolution Order), oparte na algorytmie C3 linearization.

class A:
    def speak(self):
        print("A")

class B(A):
    def speak(self):
        print("B")

class C(A):
    def speak(self):
        print("C")

class D(B, C):
    pass

D().speak()             # -> B
print(D.__mro__)        # -> (D, B, C, A, object)

Na rozmowie:

„MRO gwarantuje przewidywalną kolejność rozwiązywania metod przy wielokrotnym dziedziczeniu i unika diamentów dziedziczenia.”


6. Dekoratory

Dekorator to funkcja opakowująca inną funkcję/klasę, aby rozszerzyć jej zachowanie.

from functools import wraps

def logger(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"Wywołano {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

@logger
def greet(name):
    print(f"Cześć {name}")

Dobre praktyki: używaj functools.wraps, aby zachować metadane oryginalnej funkcji.

Na rozmowie:

„Dekoratory separują cross-cutting concerns, takie jak logowanie czy autoryzacja, od logiki biznesowej.”


7. Asynchroniczność (async / await)

Od wersji 3.5 Python oferuje natywną współbieżność opartą na asyncio.

import asyncio

async def fetch_data():
    await asyncio.sleep(1)
    return "Dane"

async def main():
    result = await fetch_data()
    print(result)

asyncio.run(main())
  • async definiuje funkcję zwracającą korutynę.
  • await oddaje kontrolę pętli zdarzeń na czas operacji I/O.
  • asyncio.run() uruchamia pętlę zdarzeń (tylko raz w głównym kontekście).

Na rozmowie:

„Asynchroniczność w Pythonie opiera się na kooperatywnym multitaskingu — zadania oddają kontrolę poprzez await, więc jedna pętla może obsłużyć wiele operacji I/O.”

Pułapki: Kod CPU-bound blokuje pętlę; do ciężkich obliczeń potrzebne są wątki lub procesy.


8. deepcopy vs shallow copy

import copy

matrix = [[1, 2], [3, 4]]
shallow = copy.copy(matrix)
deep = copy.deepcopy(matrix)

matrix[0][0] = 99
print(shallow)  # [[99, 2], [3, 4]]
print(deep)     # [[1, 2], [3, 4]]

Na rozmowie:

„Płytka kopia kopiuje referencje do obiektów zagnieżdżonych, a głęboka tworzy niezależne kopie całej struktury — kluczowe przy zagnieżdżonych kolekcjach.”


9. Wątki i procesy

  • threading — współbieżność współdzieląca pamięć, ale ograniczona przez GIL.
  • multiprocessing — równoległość z osobnymi interpreterami i pamięcią.
  • concurrent.futures — wysokopoziomowe API (ThreadPoolExecutor, ProcessPoolExecutor).
from concurrent.futures import ThreadPoolExecutor

def task(n):
    return n * n

with ThreadPoolExecutor() as executor:
    results = executor.map(task, [1, 2, 3])

Na rozmowie:

„Python odróżnia współbieżność od równoległości — I/O wymaga wątków lub asyncio, a obciążenia CPU warto przenieść do procesów.”


10. Lista, zbiór i słownik

TypKolejnośćDuplikatyKluczowa cecha
listKolekcja uporządkowana
setUnikalne elementy, operacje zbiorowe
dict✅ (od Py 3.7)Klucze unikalneSzybki dostęp po kluczu

Więcej przykładów: Python Sugar Cheatsheet.

Na rozmowie:

„Struktury danych dobieramy do wymagań dotyczących kolejności, unikalności i sposobu adresowania.”


Python 3.14 — Co Nowego

1. Leniwe adnotacje typów

Adnotacje są teraz oceniane leniwie, więc from __future__ import annotations nie jest już wymagane, a czas startu aplikacji jest krótszy.

„Typy są sprawdzane dopiero, gdy są potrzebne narzędziom takim jak mypy albo refleksji w runtime.”

2. Wielu interpreterów w jednym procesie

API interpreters pozwala tworzyć niezależne instancje interpretera, co otwiera drogę do równoległego wykonywania kodu bez blokady GIL.

import interpreters

interp = interpreters.create()
interp.run("print('Hello from another interpreter!')")

3. t-string — szablony tekstowe

Nowy typ literału (t"...") przechowuje strukturę szablonu do późniejszego wypełnienia, co przydaje się przy generowaniu HTML/SQL.

4. Zdalne debugowanie

sys.remote_exec() umożliwia zdalne sprawdzanie stanu działającej aplikacji bez jej restartu (po wcześniejszym włączeniu trybu).

5. Szybszy interpreter

Zmiany w wewnętrznej maszynie wirtualnej dają 3–5% przyspieszenia bez zmian w kodzie użytkownika.

6. Tryb free-threaded

Eksperymentalny tryb „bez GIL” został bardziej ustabilizowany — lepsza obsługa bibliotek i ostrzeżeń pochodzących z wielu wątków.

7. Narzędzia do diagnostyki asyncio

Polecenia:

python -m asyncio ps
python -m asyncio pstree

pozwalają podejrzeć aktywne zadania, kolejki i zależności.

8. Kompresja Zstandard

Nowy moduł compression.zstd integruje ZSTD z tarfile, zipfile i shutil, zapewniając szybką kompresję.

9. Lepsze komunikaty błędów

Python podpowiada poprawną nazwę przy literówkach (NameError: did you mean 'print'?).

10. Drobne usprawnienia

  • bytes.fromhex() przyjmuje teraz dowolne obiekty bajtowe.
  • Usprawnione warnings działają poprawnie w środowiskach wielowątkowych i asynchronicznych.
  • Liczne poprawki stabilności i ergonomii.

Python Fundamentals — Mini Kurs Praktyczny

1. Listy, krotki, sety i słowniki

TypSkładniaMutowalnośćKolejnośćUnikalnośćNajlepsze zastosowanie
list[1, 2, 3]Kolekcje o zmiennej długości
tuple(1, 2, 3)Dane, które nie powinny się zmieniać
set{1, 2, 3}Usuwanie duplikatów, operacje zbiorowe
dict{"a": 1, "b": 2}Klucze unikalnePrzechowywanie par klucz–wartość
names = ["Anna", "Bob", "Anna"]
unique = set(names)
print(unique)  # {'Anna', 'Bob'}

Zapamiętaj: dobór struktury dyktuje zapotrzebowanie na kolejność, mutowalność i unikalność.


2. Iteratory i generatory

Generator (yield) tworzy iterator, który produkuje wartości na żądanie.

def squares(limit):
    for i in range(limit):
        yield i * i

gen = squares(5)
print(next(gen))  # 0
print(next(gen))  # 1

yield oszczędza pamięć i jest idealny dla strumieni danych.


3. Context managers (with)

Context manager dba o otwarcie i zamknięcie zasobów.

with open("data.txt") as file:
    content = file.read()

Własny context manager:

class Connection:
    def __enter__(self):
        print("🔌 Open")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("❌ Close")

with Connection():
    print("Doing stuff...")

4. Obsługa wyjątków i raise from

try:
    result = 10 / 0
except ZeroDivisionError as err:
    raise ValueError("Nie można dzielić przez zero") from err
finally:
    print("Zawsze się wykona")

raise ... from ... zachowuje oryginalny kontekst błędu.


5. Typowanie i dataclasses

from dataclasses import dataclass

@dataclass
class User:
    name: str
    age: int

user = User("Mateusz", 32)
print(user.name)

dataclass automatycznie generuje __init__, __repr__, __eq__ i wspiera typowanie statyczne narzędziami (mypy, pydantic).


6. lambda, map, filter, zip

nums = [1, 2, 3, 4]

squares = list(map(lambda x: x * x, nums))
evens = list(filter(lambda x: x % 2 == 0, nums))
pairs = list(zip(nums, squares))

print(pairs)  # [(1, 1), (2, 4), (3, 9), (4, 16)]

Comprehensions są często czytelniejsze, ale map/filter przydają się przy funkcjach z biblioteki standardowej.


7. Enum, NamedTuple, lekkie struktury

from enum import Enum
from collections import namedtuple

class Status(Enum):
    ACTIVE = "active"
    INACTIVE = "inactive"

User = namedtuple("User", ["name", "status"])
user = User("Alice", Status.ACTIVE)

Ułatwiają walidację i eliminują „magiczne stringi”.


8. Logging zamiast print

import logging

logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)

logger.info("Program wystartował")
logger.warning("To ostrzeżenie")
logger.error("Coś poszło nie tak")

logging wspiera poziomy logów, formatery, handlery oraz wysyłkę do wielu miejsc docelowych.


9. Wirtualne środowiska: venv, poetry, pipenv

python -m venv .venv
source .venv/bin/activate   # Linux / macOS
.venv\Scripts\activate      # Windows
pip install requests
poetry init
poetry add requests
poetry run python app.py

Izolacja środowiska eliminuje konflikty wersji bibliotek między projektami.


Podsumowanie mini-kursu

TematKluczowa umiejętnośćKorzyść
Struktury danychDobór odpowiedniej kolekcjiWydajność i czytelność
Iteratory / generatoryPraca na dużych strumieniach danychOszczędność pamięci
Context managersBezpieczne zarządzanie zasobamiMniej wycieków zasobów
WyjątkiCzytelna obsługa błędówStabilniejsze aplikacje
Typowanie + dataclassesSamodokumentujący kodŁatwiejsze utrzymanie
lambda / map / filterZwięzłe operacje na kolekcjachModułowość transformacji
Enum / NamedTupleStruktury danych z ograniczeniamiEliminacja magicznych stringów
LoggingDiagnostyka aplikacjiSkalowalne logowanie
Wirtualne środowiskaIzolacja zależnościStabilne buildy

Concurrency & Parallelism Deep Dive

1. Global Interpreter Lock (GIL)

GIL to mutex w CPythonie gwarantujący, że tylko jeden wątek wykonuje bytecode naraz.

  • Upraszcza model pamięci i chroni licznik referencji przed race condition.
  • Ogranicza przyspieszenie dla zadań CPU-bound przy użyciu wątków.
  • Biblioteki w C (NumPy, TensorFlow) mogą zwalniać GIL i wykonywać się równolegle.
import threading

def cpu_task():
    x = 0
    for _ in range(10**7):
        x += 1

threads = [threading.Thread(target=cpu_task) for _ in range(4)]
for thread in threads:
    thread.start()
for thread in threads:
    thread.join()

Mimo kilku wątków kod CPU-bound nie przyspieszy z powodu GIL.


2. Async vs threading vs multiprocessing

ModelRównoległośćGILIdealne zastosowanie
asyncioIntensywne I/O (API, DB)
threading❌ (CPU) / ✅ (I/O)Operacje blokujące I/O
multiprocessing / ProcessPoolExecutor❌ (osobne interpret.)Praca CPU-bound

Łączenie async + process pool:

import asyncio
from concurrent.futures import ProcessPoolExecutor

def heavy_compute(n):
    return sum(i * i for i in range(n))

async def main():
    loop = asyncio.get_running_loop()
    with ProcessPoolExecutor() as pool:
        result = await loop.run_in_executor(pool, heavy_compute, 10_000_000)
    print(result)

asyncio.run(main())

Event loop pozostaje responsywny, a obciążenie CPU trafia do oddzielnego procesu.


3. Model mentalny wyboru narzędzia

ZadanieNarzędzieUzasadnienie
100 równoległych zapytań HTTPasyncio lub ThreadPoolExecutorWysokie I/O, mało CPU
Trening modelu MLProcessPoolExecutor, multiprocessingIntensywne obliczenia CPU/GPU
Backend FastAPIasync/awaitWielu klientów, dużo oczekiwania na I/O
Przetwarzanie strumieni danychGeneratory + ProcessPoolExecutorStrumieniowanie + równoległe liczenie

4. „Interview ready” sound bites

  • GIL: „Global Interpreter Lock to mechanizm bezpieczeństwa CPythona — upraszcza zarządzanie pamięcią, ale wymaga procesów, jeśli chcemy pełnego wykorzystania wielu rdzeni.”
  • Async interplay: „W aplikacjach async ciężkie obliczenia przenosimy do ProcessPoolExecutor, dzięki czemu pętla zdarzeń nie blokuje się na operacjach CPU.”

Python Under the Hood

1. Warstwy CPythona

Twoje skrypty Python → Biblioteka standardowa → Interpreter CPython (C) →
Moduły C/C++ / Rust → System operacyjny → Sprzęt

Python jest „klejem” spinającym wysoko poziomowy kod z wysokowydajnymi bibliotekami natywnymi.

2. Dlaczego Python używa C/C++

PowódZnaczenie
WydajnośćKrytyczne fragmenty są kompilowane do kodu maszynowego.
InteroperacyjnośćC jest wspólnym językiem dla wielu platform i bibliotek.
ReuseMożliwość wykorzystania sprawdzonych bibliotek (BLAS, LAPACK, OpenSSL).
EkosystemMożliwość pisania własnych rozszerzeń i integracji z istniejącym kodem.

3. Przykłady bibliotek opartych na C/C++

BibliotekaZakresWarstwa natywna
NumPyObliczenia macierzoweC (BLAS/LAPACK)
pandasDataFrameC / Cython
TensorFlowDeep LearningC++
PyTorchDeep LearningC++ / CUDA
OpenCVPrzetwarzanie obrazuC++
sqlite3Relacyjna baza danychC
uvloopEvent loopC (libuv)
orjson, ruffJSON / lintRust

4. Jak wyglądają rozszerzenia w C

#include <Python.h>

static PyObject* add(PyObject* self, PyObject* args) {
    int a, b;
    if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
        return NULL;
    }
    return PyLong_FromLong(a + b);
}

static PyMethodDef methods[] = {
    {"add", add, METH_VARARGS, "Add two numbers"},
    {NULL, NULL, 0, NULL}
};

static struct PyModuleDef module = {
    PyModuleDef_HEAD_INIT, "mymodule", NULL, -1, methods
};

PyMODINIT_FUNC PyInit_mymodule(void) {
    return PyModule_Create(&module);
}

Składamy moduł w C, a następnie importujemy go jak zwykły moduł w Pythonie.

5. Alternatywne mosty

  • Cython — Pythonowa składnia kompilowana do C.
  • ctypes / cffi — dynamiczne ładowanie bibliotek C.
  • PyBind11 — nowoczesne API dla C++.
  • PyO3 / maturin — pisanie rozszerzeń w Rust.

6. NumPy jako przykład

import numpy as np

arr = np.arange(10_000_000)
print(arr.mean())

Obliczenia odbywają się w zminimalizowanej pętli C, a Python zapewnia jedynie interfejs wysokiego poziomu.

7. Odpowiedź na pytanie „Dlaczego Python jest wolny?”

„Sam bytecode CPythona jest powolniejszy niż C z powodu interpretacji i GIL. Jednak większość pracochłonnych bibliotek jest napisana w C/C++, więc ciężkie operacje wykonują się natywnie, a Python pełni rolę bardzo produktywnej warstwy sterującej.”


Końcowe podsumowanie

ObszarDlaczego ważny
Interview EssentialsGotowe odpowiedzi na najczęstsze pytania rekrutacyjne
Nowości w Pythonie 3.14Świadomość zmian języka i narzędzi
FundamentyPowtórka kluczowych struktur, idiomów i narzędzi
RównoległośćZrozumienie ograniczeń GIL i strategii skalowania
Architektura CPythonaUmiejętność wytłumaczenia, jak Python korzysta z C/C++

Te sekcje tworzą bazę wiedzy, którą można rozwijać podczas kolejnych sesji lub uzupełniać własnymi przykładami oraz linkami do projektów.