Python
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ł
gcwykrywa 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
| Cecha | Lista (list) | Krotka (tuple) |
|---|---|---|
| Mutowalność | ✅ | ❌ |
| Typowy zapis | [1, 2, 3] | (1, 2, 3) |
| Wydajność | Wolniejsza (dynamiczna) | Szybsza (niemutowalna) |
| Zastosowanie | Zmienne kolekcje | Stał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())
asyncdefiniuje funkcję zwracającą korutynę.awaitoddaje 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
| Typ | Kolejność | Duplikaty | Kluczowa cecha |
|---|---|---|---|
list | ✅ | ✅ | Kolekcja uporządkowana |
set | ❌ | ❌ | Unikalne elementy, operacje zbiorowe |
dict | ✅ (od Py 3.7) | Klucze unikalne | Szybki 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
mypyalbo 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
warningsdział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
| Typ | Składnia | Mutowalność | 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 unikalne | Przechowywanie 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
yieldoszczę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
| Temat | Kluczowa umiejętność | Korzyść |
|---|---|---|
| Struktury danych | Dobór odpowiedniej kolekcji | Wydajność i czytelność |
| Iteratory / generatory | Praca na dużych strumieniach danych | Oszczędność pamięci |
| Context managers | Bezpieczne zarządzanie zasobami | Mniej wycieków zasobów |
| Wyjątki | Czytelna obsługa błędów | Stabilniejsze aplikacje |
| Typowanie + dataclasses | Samodokumentujący kod | Łatwiejsze utrzymanie |
lambda / map / filter | Zwięzłe operacje na kolekcjach | Modułowość transformacji |
Enum / NamedTuple | Struktury danych z ograniczeniami | Eliminacja magicznych stringów |
| Logging | Diagnostyka aplikacji | Skalowalne logowanie |
| Wirtualne środowiska | Izolacja zależności | Stabilne 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
| Model | Równoległość | GIL | Idealne zastosowanie |
|---|---|---|---|
asyncio | ❌ | ✅ | Intensywne 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
| Zadanie | Narzędzie | Uzasadnienie |
|---|---|---|
| 100 równoległych zapytań HTTP | asyncio lub ThreadPoolExecutor | Wysokie I/O, mało CPU |
| Trening modelu ML | ProcessPoolExecutor, multiprocessing | Intensywne obliczenia CPU/GPU |
| Backend FastAPI | async/await | Wielu klientów, dużo oczekiwania na I/O |
| Przetwarzanie strumieni danych | Generatory + ProcessPoolExecutor | Strumieniowanie + 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ód | Znaczenie |
|---|---|
| Wydajność | Krytyczne fragmenty są kompilowane do kodu maszynowego. |
| Interoperacyjność | C jest wspólnym językiem dla wielu platform i bibliotek. |
| Reuse | Możliwość wykorzystania sprawdzonych bibliotek (BLAS, LAPACK, OpenSSL). |
| Ekosystem | Możliwość pisania własnych rozszerzeń i integracji z istniejącym kodem. |
3. Przykłady bibliotek opartych na C/C++
| Biblioteka | Zakres | Warstwa natywna |
|---|---|---|
| NumPy | Obliczenia macierzowe | C (BLAS/LAPACK) |
| pandas | DataFrame | C / Cython |
| TensorFlow | Deep Learning | C++ |
| PyTorch | Deep Learning | C++ / CUDA |
| OpenCV | Przetwarzanie obrazu | C++ |
| sqlite3 | Relacyjna baza danych | C |
| uvloop | Event loop | C (libuv) |
| orjson, ruff | JSON / lint | Rust |
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
| Obszar | Dlaczego ważny |
|---|---|
| Interview Essentials | Gotowe odpowiedzi na najczęstsze pytania rekrutacyjne |
| Nowości w Pythonie 3.14 | Świadomość zmian języka i narzędzi |
| Fundamenty | Powtórka kluczowych struktur, idiomów i narzędzi |
| Równoległość | Zrozumienie ograniczeń GIL i strategii skalowania |
| Architektura CPythona | Umieję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.