python-interview-questions

Read in other languages: English 🇺🇸, Polski 🇵🇱, German 🇩🇪, French 🇫🇷, Spanish 🇪🇸, Ukraiński 🇺🇦.

Python Python logo

Najpopularniejsze pytania i odpowiedzi rekrutacyjne z Pythona

1. Czym jest Python i jakie są jego główne cechy? #### Python **Python** to wysokopoziomowy język ogólnego przeznaczenia, nastawiony na czytelność, szybki rozwój i rozbudowany standardowy zestaw narzędzi. Główne cechy: - **Prosta składnia**: kod łatwo czytać i utrzymywać. - **Interpretowany model wykonania**: szybki cykl zmian bez ręcznego etapu kompilacji. - **Wieloplatformowość**: ten sam kod działa na Linuxie, macOS i Windowsie. - **Wieloparadygmatowość**: podejścia proceduralne, OOP i funkcyjne w jednym projekcie. - **Silny ekosystem**: `pip`, `venv`, `pyproject.toml`, tysiące gotowych bibliotek. - **Nowoczesne możliwości Pythona 3.10+**: type hints, `dataclass`, `async/await`, `match/case`, generatory, menedżery kontekstu. Przykład funkcji w stylu production: ```python from dataclasses import dataclass @dataclass(slots=True) class User: name: str active: bool def process_users(users: list[User]) -> list[str]: return [user.name for user in users if user.active] ``` **W skrócie:** - Python przyspiesza rozwój dzięki prostej składni i dużej bibliotece standardowej. - Język nadaje się do backendu, automatyzacji, data/ML, testowania i DevOps. - W Pythonie 3.10+ kluczowe praktyki to adnotacje typów, async I/O i nowoczesna biblioteka standardowa.
2. Jakie są kluczowe zalety Pythona? #### Python Kluczowe zalety Pythona w production: - wysoka szybkość rozwoju dzięki zwięzłej składni; - duża biblioteka standardowa (`pathlib`, `itertools`, `collections`, `asyncio`); - dojrzały ekosystem pakietów dla backendu, data, automatyzacji i testowania; - przenośność kodu między systemami operacyjnymi; - dobre wsparcie dla typowania (`typing`, `mypy`, `pyright`) i nowoczesnych praktyk. **W skrócie:** - Python skraca time-to-market. - Daje wiele gotowych narzędzi bez dodatkowych zależności. - Nadaje się zarówno do MVP, jak i do skalowalnych serwisów.
3. Czym Python różni się od języków kompilowanych? #### Python Python zwykle jest wykonywany przez interpreter: kod jest kompilowany do bajtkodu i uruchamiany w czasie wykonania (CPython VM). W językach kompilowanych (C/C++, Rust) zazwyczaj występuje wcześniejsza kompilacja do kodu maszynowego. Praktyczne konsekwencje: - Python jest szybszy w rozwoju i prototypowaniu. - Natywnie kompilowane języki są zwykle szybsze w zadaniach CPU-bound. - W Pythonie wydajność często poprawia się algorytmami, profilowaniem i rozszerzeniami C. **W skrócie:** - Python optymalizuje szybkość rozwoju. - Kompilacja do kodu maszynowego zwykle daje lepszą surową wydajność. - Wybór zależy od domeny i wymagań dotyczących opóźnień oraz przepustowości.
4. Co oznacza dynamiczne typowanie w Pythonie? #### Python Dynamiczne typowanie oznacza, że typ jest przypisany do obiektu, a nie do nazwy zmiennej. Nazwa może wskazywać na wartości różnych typów w różnym czasie wykonania. ```python value = 10 # int value = "10" # str ``` Typy są sprawdzane podczas wykonania, dlatego błędy typów pojawiają się w w czasie wykonania, jeśli nie używa się statycznego analizatora typów. **W skrócie:** - W Pythonie typ ma obiekt, a nie zmienna. - Typ może się zmieniać przy ponownym przypisaniu nazwy. - Type hints dodają kontrolę przed uruchomieniem kodu.
5. Co oznacza strong typing w Pythonie? #### Python Strong typing w Pythonie oznacza, że interpreter nie wykonuje niebezpiecznych, niejawnych konwersji między niezgodnymi typami. ```python 1 + "2" # TypeError ``` Dla operacji na różnych typach potrzebne jest jawne rzutowanie: ```python 1 + int("2") # 3 ``` **W skrócie:** - Python jest dynamicznie typowany, ale rygorystyczny pod względem zgodności typów. - Niebezpieczne niejawne konwersje są blokowane błędem. - Jawne rzutowanie czyni zachowanie przewidywalnym.
6. Czym jest REPL i kiedy się go używa? #### Python REPL (Read-Eval-Print Loop) to tryb interaktywny, w którym wpisujesz wyrażenie, natychmiast otrzymujesz wynik i szybko weryfikujesz hipotezy. Zastosowania: - sprawdzenie API biblioteki; - szybkie przetestowanie wyrażenia lub algorytmu; - zbadanie danych przed implementacją w module. Narzędzia: standardowy `python`, `ipython`, `ptpython`. **W skrócie:** - REPL daje najszybszą pętlę feedbacku. - Jest wygodny do eksperymentów i debugowania. - Nie zastępuje testów, ale skraca czas sprawdzania pomysłów.
7. Czym są literały w Pythonie? Podaj przykłady różnych typów literałów. #### Python Literał to stała wartość zapisana bezpośrednio w kodzie. ```python name = "Ada" # str literal count = 42 # int literal ratio = 3.14 # float literal enabled = True # bool literal items = [1, 2, 3] # list literal config = {"retries": 3} # dict literal flags = {"a", "b"} # set literal point = (10, 20) # tuple literal raw = b"abc" # bytes literal ``` **W skrócie:** - Literały to wbudowane stałe wartości w kodzie. - Każdy podstawowy typ ma własną składnię literału. - Są często używane do inicjalizacji danych.
8. Czym są keywords w Pythonie? #### Python Keywords to zarezerwowane słowa języka, które mają specjalne znaczenie składniowe i nie mogą być nazwami zmiennych. Przykłady: `if`, `for`, `class`, `def`, `match`, `case`, `try`, `except`, `async`, `await`. Listę można sprawdzić: ```python import keyword print(keyword.kwlist) ``` **W skrócie:** - Keywords tworzą składnię Pythona. - Nie można ich używać jako identyfikatorów. - Lista jest dostępna przez moduł `keyword`.
9. Czym jest zmienna w Pythonie? #### Python Zmienna w Pythonie to nazwa (reference), która wskazuje na obiekt w pamięci. Przypisanie wiąże nazwę z obiektem, a nie „wkłada wartość do pudełka”. ```python x = [1, 2] y = x y.append(3) # x i y wskazują na tę samą listę ``` **W skrócie:** - Zmienna jest referencją do obiektu. - Kilka nazw może wskazywać na ten sam mutable object. - To ważne dla zrozumienia kopiowania i efektów ubocznych.
10. Czym są `pass` i `...` (Ellipsis) w Pythonie? #### Python `pass` to instrukcja-zagłuszka: nic nie robi, ale pozwala zapisać poprawny składniowo pusty blok. `...` (Ellipsis) to osobny obiekt `Ellipsis`. Często jest używany jako znacznik „jeszcze niezaimplementowane”, w type hints i bibliotekach, na przykład NumPy. ```python def feature() -> None: pass PLACEHOLDER = ... ``` **W skrócie:** - `pass` jest przydatny w pustych blokach kodu. - `...` jest wartością-obiektem, a nie słowem kluczowym. - Oba są używane jako tymczasowe zagłuszki, ale mają różną semantykę.
11. Czym jest PEP i jak wpływa na rozwój Pythona? #### Python PEP (Python Enhancement Proposal) to oficjalny dokument opisujący nową funkcję, standard lub proces w ekosystemie Pythona. Przez PEP przechodzą: - dyskusja nad projektem; - argumentacja techniczna; - decyzja o przyjęciu lub odrzuceniu; - standaryzacja praktyk. Przykłady: PEP 8 (styl), PEP 484 (type hints), PEP 634 (pattern matching). **W skrócie:** - PEP to mechanizm ewolucji języka i narzędzi. - Sprawia, że zmiany są przejrzyste i sformalizowane. - Wiele współczesnych praktyk w Pythonie zostało utrwalonych właśnie przez PEP.
12. Czym jest PEP 8 i po co jest potrzebny? #### Python PEP 8 to oficjalny przewodnik po stylu kodu Pythona: nazewnictwo, formatowanie, wcięcia, importy, długość linii i czytelność konstrukcji. Dlaczego jest potrzebny: - kod ma jednolity styl w zespole; - code review przebiega szybciej; - jest mniej szumu w diffie; - rośnie maintainability. W praktyce styl automatyzuje się przez `ruff format` albo `black` + `ruff`. **W skrócie:** - PEP 8 standaryzuje styl kodu Pythona. - Chodzi o czytelność i utrzymanie, a nie o wydajność. - Przestrzeganie zasad najlepiej automatyzować narzędziami.
13. Jakie nowe możliwości pojawiły się we współczesnych wersjach Pythona (3.10+)? #### Python Kluczowe możliwości współczesnego Pythona: - `match/case` (structural pattern matching); - ulepszona składnia i komunikaty o błędach; - typy union przez `|` (`int | None`); - `typing.Self`, `typing.TypeAlias`, `typing.override`; - generics w stylu PEP 695 (`class Box[T]: ...`, `def f[T](...) -> ...`); - `tomllib` w bibliotece standardowej. W praktyce zmniejsza to boilerplate i poprawia niezawodność typowanego kodu. **W skrócie:** - Python 3.10+ znacząco poprawił składnię i typing. - `match/case` i nowoczesny `typing` mają najbardziej zauważalny wpływ na kod. - Nowych funkcji warto domyślnie używać w nowym kodzie.
14. Czym jest docstring w Pythonie? #### Python Docstring to łańcuch dokumentacyjny, pierwszy wyrażenie w module, klasie lub funkcji. Jest dostępny przez `__doc__` i używany przez IDE, `help()` oraz generatory dokumentacji. ```python def normalize_email(email: str) -> str: """Return lowercase email without surrounding spaces.""" return email.strip().lower() ``` Zaleca się opisywać: co robi funkcja, argumenty, wartość zwracaną i wyjątki. **W skrócie:** - Docstring to wbudowana dokumentacja w kodzie. - Działa jako źródło dla `help()` i automatycznego generowania dokumentacji. - Dobry docstring zmniejsza potrzebę czytania implementacji.
15. Jak działają wcięcia (indentation) w Pythonie? #### Python W Pythonie wcięcia definiują bloki kodu (ciało `if`, `for`, `def`, `class`). Oznacza to, że wcięcie jest częścią składni, a nie tylko stylem. ```python if is_ready: run_task() else: stop_task() ``` Mieszanie tabów i spacji może prowadzić do `IndentationError` albo niepoprawnej struktury bloku. **W skrócie:** - Wcięcie w Pythonie definiuje strukturę programu. - Nieprawidłowe wcięcie psuje wykonanie. - Używaj spójnego stylu, najlepiej 4 spacji.
16. Ile spacji należy stosować do wcięcia zgodnie z PEP 8 i dlaczego ważne jest zachowanie jednolitych wcięć? #### Python PEP 8 zaleca **4 spacje** na jeden poziom wcięcia. Dlaczego to istotne: - jednolita struktura bloków w całym projekcie; - przewidywalny wygląd w różnych edytorach; - mniej błędów przez konflikty tab/spacja; - czytelniejszy diff w Git. **W skrócie:** - Standardowe wcięcie to 4 spacje. - Jeden styl eliminuje całą klasę błędów formatowania. - Bezpośrednio poprawia to czytelność i utrzymanie kodu.
17. Jaka jest różnica między `ruff` a `black` pod względem funkcjonalności i użycia? #### Python `black` to formatter kodu o stałych regułach. `ruff` to szybki linter, a także formatter i auto-fixer wielu reguł (PEP 8, importy, potencjalne bugi, uproszczenia składni). Praktyczne podejścia: - albo `ruff check --fix` + `ruff format`; - albo `ruff` do lintu + `black` do formatowania. **W skrócie:** - `black` koncentruje się na formatowaniu. - `ruff` pokrywa linting i część automatycznych poprawek. - W nowoczesnych projektach często wystarcza sam `ruff`.
18. Wyjaśnij przeznaczenie type annotations w Pythonie i podaj przykład funkcji z type annotations. #### Python Type annotations opisują oczekiwane typy argumentów i wartości zwracanej. Poprawiają autouzupełnianie, analizę statyczną i czytelność API. ```python def process_users(users: list[dict[str, object]]) -> list[str]: return [str(user["name"]) for user in users if bool(user.get("active"))] ``` Adnotacje same w sobie nie wykonują walidacji w czasie działania, ale pomagają wykrywać błędy na etapie CI przez `mypy` lub `pyright`. **W skrócie:** - Type hints dokumentują kontrakt funkcji. - Dają wczesne wykrywanie błędów przez static checking. - Podnoszą jakość API w dużych codebase'ach.
19. Czym jest debugging i dlaczego to ważna umiejętność dla programistów? #### Python Debugging to systematyczne szukanie przyczyny niepoprawnego zachowania kodu i jej usuwanie. To nie tylko „znaleźć buga”, ale odtworzyć go, zlokalizować i zweryfikować fix. Podstawowy cykl: - odtworzyć problem; - zawęzić obszar kodu; - sprawdzić hipotezę logami lub debuggerem; - dodać test, który utrwala scenariusz. **W skrócie:** - Debugging zmniejsza MTTR i liczbę regresji. - Działa najlepiej jako proces, a nie chaotyczne szukanie. - Zakończenie debugowania to: fix + test + dodatkowa weryfikacja.
20. Wyjaśnij, do czego służy używanie funkcji `print` do debugowania. Podaj przykład sytuacji, w której to podejście jest przydatne. #### Python `print`-debugging to szybki sposób na sprawdzenie wartości zmiennych i kolejności wykonania bez uruchamiania bardziej złożonych narzędzi. Jest przydatny, gdy trzeba szybko sprawdzić hipotezę w lokalnym skrypcie: ```python def parse_port(raw: str) -> int: value = raw.strip() print(f"raw={raw!r} value={value!r}") return int(value) ``` Dla kodu produkcyjnego lepiej przejść na `logging`, aby mieć poziomy logów i kontrolowane wyjście. **W skrócie:** - `print` nadaje się do krótkiej, lokalnej diagnostyki. - Szybko pokazuje stan zmiennych w problematycznym miejscu. - Do stabilnej diagnostyki w serwisie używaj `logging`.
21. Opisz, jak można używać Python Debugger (PDB) do debugowania. Jakie zalety ma PDB w porównaniu z `print`? #### Python `pdb` pozwala zatrzymywać wykonanie programu, przechodzić po liniach, sprawdzać stan zmiennych i stos wywołań. Podstawowe użycie: ```python import pdb def compute(x: int) -> int: pdb.set_trace() return x * 2 ``` Kluczowe komendy: `n` (next), `s` (step), `c` (continue), `p expr` (print expr), `l` (list), `bt` (backtrace). **W skrócie:** - `pdb` daje interaktywną kontrolę nad wykonaniem. - Jest skuteczniejszy niż `print` w bardziej złożonych scenariuszach. - Pozwala diagnozować stan bez zaśmiecania kodu logami.
22. Jakie strategie można stosować do debugowania pętli i funkcji w Pythonie? #### Python Praktyczne strategie: - zlokalizować błąd przez minimalny odtwarzalny przykład; - logować niezmienniki podczas iteracji pętli; - ustawiać breakpoint na wejściu i wyjściu z funkcji; - sprawdzać przypadki brzegowe (puste dane, `None`, duże wolumeny); - pokrywać problematyczną ścieżkę testem. Dla pętli warto logować indeks i kluczowe stany pośrednie. **W skrócie:** - Zaczynaj od odtworzenia i zawężenia problemu. - Sprawdzaj niezmienniki i warunki brzegowe. - Kończ fixem i testem, który łapie regresję.
23. Jaki wpływ mają długotrwałe funkcje na wydajność programu? #### Python Długotrwałe funkcje zwiększają latency, blokują workery lub wątki i pogarszają przepustowość serwisu. Ryzyka: - wolne odpowiedzi API; - timeouty; - wzrost kolejek zadań; - gorsze wykorzystanie CPU i I/O. Podejście: profilować (`cProfile`), rozbijać na mniejsze kroki, używać generatorów i przetwarzania strumieniowego, wynosić ciężkie obliczenia do `multiprocessing` albo do tła. **W skrócie:** - Długie funkcje bezpośrednio uderzają w latency. - Optymalizację opiera się na profilowaniu, a nie na intuicji. - Architektonicznie lepiej rozdzielać pracę CPU-bound i I/O-bound.
24. Czym jest logging i dlaczego lepiej używać go zamiast `print`? #### Python `logging` to standardowy mechanizm rejestrowania zdarzeń z poziomami (`DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`), formatami i handlerami (console, file). Dlaczego jest lepszy od `print`: - kontrolowane poziomy szczegółowości; - ustrukturyzowany format; - scentralizowana konfiguracja; - możliwość integracji ze stackiem observability. **W skrócie:** - `logging` nadaje się do produkcji, `print` nie. - Poziomy logów dają kontrolę nad szumem. - Logi powinny być ustrukturyzowane i spójne.
25. Czym jest traceback? #### Python Traceback to stos wywołań, który Python pokazuje przy wyjątku: gdzie wykonanie się zaczęło, przez jakie funkcje przeszedł kod i gdzie dokładnie wystąpił błąd. Zastosowanie: - szybko znaleźć plik i linię źródła błędu; - zrozumieć ścieżkę wykonania do awarii; - zbudować dokładny test odtwarzający problem. **W skrócie:** - Traceback to „trasa” do błędu. - Najcenniejsza część to ostatnie klatki stosu i typ wyjątku. - Analiza tracebacku przyspiesza znalezienie root cause.
26. Jakie podstawowe typy danych istnieją w Pythonie? #### Python Podstawowe typy built-in: - liczbowe: `int`, `float`, `complex`; - logiczny: `bool`; - tekstowe i bajtowe: `str`, `bytes`, `bytearray`; - kolekcje: `list`, `tuple`, `set`, `dict`, `frozenset`; - specjalne: `NoneType` (`None`). Ważne jest rozumienie mutability: - mutable: `list`, `dict`, `set`, `bytearray`; - immutable: `int`, `str`, `tuple`, `frozenset`. **W skrócie:** - Python ma bogaty zestaw podstawowych typów „out of the box”. - Wybór struktury danych wpływa na złożoność operacji. - Mutability określa zachowanie kopiowania i efekty uboczne.
27. Jaka jest różnica między zwykłym dzieleniem (`/`) a dzieleniem całkowitym (`//`) w Pythonie? #### Python `/` wykonuje zwykłe dzielenie i zawsze zwraca `float`. `//` wykonuje dzielenie floor: zwraca część całkowitą zaokrągloną w dół (do `-∞`), a typem przy całkowitych operandach jest zwykle `int`. ```python 7 / 2 # 3.5 7 // 2 # 3 -7 // 2 # -4 ``` **W skrócie:** - `/` -> wynik rzeczywisty. - `//` -> zaokrąglenie w dół do liczby całkowitej. - Dla liczb ujemnych `//` nie jest równoważne „ucięciu do zera”.
28. Wyjaśnij użycie operatora modulo (`%`) w Pythonie. Jak można go użyć, aby określić, czy liczba jest parzysta czy nieparzysta? #### Python Operator `%` zwraca resztę z dzielenia. Sprawdzenie parzystości: ```python def is_even(n: int) -> bool: return n % 2 == 0 ``` Jeśli `n % 2 == 0`, liczba jest parzysta, w przeciwnym razie nieparzysta. Typowe zadania: indeksy cykliczne, podział na grupy, obliczenia kalendarzowe. **W skrócie:** - `%` zwraca remainder. - `n % 2` to standardowy test parzystości. - Często jest używany do logiki cyklicznej.
29. Jak Python pracuje z dużymi liczbami całkowitymi i jakie są ograniczenia przy pracy z bardzo dużymi liczbami? #### Python `int` w Pythonie ma dowolną precyzję (arbitrary precision), czyli nie jest ograniczony do 32 lub 64 bitów jak w wielu innych językach. Ograniczenia są praktyczne: - pamięć procesu; - czas obliczeń dla bardzo dużych wartości; - koszt operacji rośnie wraz ze wzrostem liczby cyfr. **W skrócie:** - Nie ma klasycznego przepełnienia `int`. - Ograniczeniem są zasoby maszyny, a nie stały rozmiar bitowy. - Przy dużych obliczeniach kluczowe są algorytmy i profilowanie.
30. Jakie znaczenie ma obsługa dzielenia przez zero w Pythonie i jak zapobiec `ZeroDivisionError` w kodzie? #### Python Dzielenie przez zero powoduje `ZeroDivisionError`. Trzeba to obsługiwać jawnie, jeśli dzielnik pochodzi z wejścia zewnętrznego albo jest obliczany dynamicznie. ```python def safe_div(a: float, b: float) -> float | None: if b == 0: return None return a / b ``` W krytycznych scenariuszach używaj `try/except` oraz logowania kontekstu. **W skrócie:** - Dzielenie przez zero to kontrolowany błąd czasu wykonania. - Najprostsza ochrona to sprawdzenie dzielnika przed operacją. - Dla danych zewnętrznych dodawaj zabezpieczenia i diagnostykę.
31. Opisz użycie modułu `random` w Pythonie. Jakie są najczęściej używane funkcje tego modułu? #### Python `random` jest używany do pseudolosowych wartości w symulacjach, danych testowych i zadaniach non-crypto. Popularne funkcje: - `random()` — liczba z przedziału `[0.0, 1.0)`; - `randint(a, b)` — liczba całkowita z zakresu; - `randrange(start, stop, step)` — jak range, ale losowy element; - `choice(seq)` / `choices(seq, k=...)`; - `shuffle(list_)` — tasuje listę in-place; - `sample(population, k)` — unikalna próbka. Dla kryptografii używaj `secrets`, a nie `random`. **W skrócie:** - `random` nadaje się do zwykłej, aplikacyjnej losowości. - Najczęściej używa się `randint`, `choice`, `shuffle`, `sample`. - Do zadań security-sensitive potrzebny jest `secrets`.
32. Jak pracować w Pythonie z liczbami o lepszej precyzji? #### Python Dla finansowych i dokładnych obliczeń dziesiętnych używaj `decimal.Decimal`, a nie `float`. ```python from decimal import Decimal total = Decimal("0.1") + Decimal("0.2") # Decimal('0.3') ``` Dla liczb wymiernych przydatny jest `fractions.Fraction`. **W skrócie:** - `float` jest wygodny, ale ma błędy reprezentacji binarnej. - Do dokładnej arytmetyki dziesiętnej wybieraj `Decimal`. - Typ liczby powinien odpowiadać domenie problemu.
33. Czym są znaki escape w stringach Pythona i jak się ich używa? Podaj przykłady dla `\n`, `\t`, `\r`, `\"` i `\'`. #### Python Sekwencje escape to specjalne kombinacje z `\`, które kodują znaki specjalne wewnątrz stringa. - `\n` — nowa linia - `\t` — tabulacja - `\r` — powrót karetki - `\"` — cudzysłów w stringu z `"` - `\'` — apostrof w stringu z `'` ```python text = "A\tB\n\"quoted\"\nI\'m here\rX" ``` **W skrócie:** - Znaki escape sterują formatowaniem stringa. - Pozwalają wstawiać cudzysłowy bez łamania składni. - Dla ścieżek i regexów często wygodnie używać raw stringów `r"..."`.
34. Wyjaśnij użycie metod `strip`, `lstrip` i `rstrip` w Pythonie. Czym się różnią? #### Python Metody działają na brzegach stringa: - `strip()` — usuwa znaki z obu stron; - `lstrip()` — tylko z lewej; - `rstrip()` — tylko z prawej. Domyślnie usuwają whitespace albo konkretny zestaw znaków: ```python " hello ".strip() # "hello" "--id--".strip("-") # "id" ``` **W skrócie:** - Rodzina `strip` nie zmienia stringa in-place, tylko zwraca nowy. - Różnica dotyczy wyłącznie strony czyszczenia. - Często jest używana na danych wejściowych.
35. Opisz przeznaczenie metody `count` w stringach. Jak działa? #### Python `str.count(sub[, start[, end]])` liczy liczbę niepokrywających się wystąpień podciągu `sub` w wybranym zakresie. ```python "banana".count("an") # 2 "banana".count("a", 2) # 2 ``` Zwraca `0`, jeśli nie ma żadnych wystąpień. **W skrócie:** - `count` szybko zwraca liczbę wystąpień podciągu. - Obsługuje ograniczenie wyszukiwania przez `start/end`. - Liczy niepokrywające się wystąpienia.
36. Jak działa metoda `join` w Pythonie i do czego najczęściej się jej używa? #### Python `sep.join(iterable)` łączy sekwencję stringów w jeden string przy użyciu separatora `sep`. ```python names = ["Ada", "Linus", "Guido"] result = ", ".join(names) # "Ada, Linus, Guido" ``` Typowe zastosowania: tworzenie linii podobnych do CSV, logów, fragmentów SQL, ścieżek URL i komunikatów. **W skrócie:** - `join` to standardowy i szybki sposób łączenia stringów. - Wywołuje się go na separatorze, a nie na liście. - Jest wydajniejszy niż wielokrotne `+=` w pętli.
37. Czym jest slicing w Pythonie i jak za jego pomocą pobierać podciągi? Podaj przykłady z dodatnimi i ujemnymi indeksami. #### Python Slicing to wybór fragmentu sekwencji przez `[start:stop:step]`. ```python s = "python" s[1:4] # "yth" s[:2] # "py" s[-3:] # "hon" s[::-1] # "nohtyp" ``` `start` jest włączony, `stop` nie jest włączony. **W skrócie:** - Slicing działa dla stringów, list i krotek. - Ujemne indeksy są liczone od końca. - To podstawowe narzędzie obróbki sekwencji bez pętli.
38. Wyjaśnij metodę `replace` dla stringów. Jak za jej pomocą zamienić kilka wystąpień podciągu? #### Python `str.replace(old, new, count=-1)` zwraca nowy string, w którym `old` został zamieniony na `new`. Domyślnie zamieniane są wszystkie wystąpienia. ```python "foo bar foo".replace("foo", "baz") # "baz bar baz" "foo bar foo".replace("foo", "baz", 1) # "baz bar foo" ``` **W skrócie:** - `replace` nie zmienia stringa in-place. - Bez `count` zamienia wszystkie wystąpienia. - `count` pozwala kontrolować liczbę zamian.
39. Jak działa metoda `split` w stringach? #### Python `split(sep=None, maxsplit=-1)` dzieli string na listę podciągów. - bez `sep` dzieli po dowolnych białych znakach; - z `sep` dzieli po konkretnym separatorze; - `maxsplit` ogranicza liczbę podziałów. ```python "a,b,c".split(",") # ["a", "b", "c"] "a b c".split() # ["a", "b", "c"] "k=v=x".split("=", 1) # ["k", "v=x"] ``` **W skrócie:** - `split` zamienia string na listę tokenów. - `sep=None` ma specjalne zachowanie dla whitespace. - `maxsplit` jest przydatny przy parsowaniu formatów key/value.
40. Jak działa konwersja typów (type casting)? #### Python Type casting to jawna konwersja wartości między typami przez konstruktory: `int()`, `float()`, `str()`, `bool()`, `list()`, `tuple()`, `set()`, `dict()`. ```python age = int("42") price = float("19.99") text = str(10) ``` Niepoprawne dane powodują wyjątek (`ValueError`, `TypeError`), dlatego dla wejścia zewnętrznego potrzebna jest walidacja. **W skrócie:** - Python udostępnia jawne funkcje konwersji typów. - Nie wszystkie wartości można bezpiecznie skonwertować. - Dla user input potrzebne są walidacja i obsługa wyjątków.
41. Jak Python automatycznie konwertuje różne typy danych na wartości boolean? #### Python W kontekście boolean Python stosuje reguły truthiness. Wartości podobne do `False`: - `False`, `None`; - liczby zerowe: `0`, `0.0`, `0j`; - puste kolekcje: `""`, `[]`, `{}`, `set()`, `tuple()`, `range(0)`. Wszystko inne jest zwykle `True`. ```python bool([]) # False bool("0") # True ``` **W skrócie:** - Konwersja boolean opiera się na regułach truthy/falsy. - Puste i zerowe -> `False`. - Niepusty string `"0"` nadal jest `True`.
42. Wyjaśnij, jak zamienić string na liczbę całkowitą albo zmiennoprzecinkową w Pythonie. Co się stanie, jeśli stringa nie da się przekonwertować na liczbę? #### Python Do konwersji używaj `int()` i `float()`: ```python count = int("42") ratio = float("3.14") ``` Jeśli string jest niepoprawny, Python zgłasza `ValueError`. ```python def parse_int(value: str) -> int | None: try: return int(value) except ValueError: return None ``` **W skrócie:** - `int()` i `float()` wykonują jawną konwersję ze stringa. - Nieprawidłowy format -> `ValueError`. - Dla danych zewnętrznych potrzebny jest `try/except`.
43. Co robi Python przy porównywaniu różnych typów danych, takich jak liczby całkowite i zmiennoprzecinkowe albo liczby całkowite i boolean? #### Python Python pozwala na porównania liczbowe zgodnych typów numeric. - `int` i `float` są porównywane według wartości. - `bool` jest podklasą `int`: `False == 0`, `True == 1`. ```python 1 == 1.0 # True True == 1 # True False < 1 # True ``` Dla niezgodnych typów, na przykład `int` i `str`, porównanie porządku (`<`, `>`) powoduje `TypeError`. **W skrócie:** - `int`, `float` i `bool` mają wspólną semantykę numeric. - `bool` zachowuje się jak `0/1` w porównaniach. - Niezgodne typy nie są porównywane operatorami porządku.
44. Jak Python obsługuje porównania między listami a set? #### Python `list` i `set` to różne typy o różnej semantyce, dlatego bezpośrednie porównanie porządku między nimi nie jest wspierane. ```python [1, 2] == {1, 2} # False [1, 2] < {1, 2} # TypeError ``` Jeśli trzeba porównać skład elementów, najpierw ujednolić typ: ```python set([1, 2]) == {1, 2} # True ``` **W skrócie:** - `list` i `set` są porównywane jako różne struktury danych. - `==` między nimi zwykle daje `False`. - Aby porównać sensownie zawartość, najpierw sprowadź do jednego typu.
45. Opisz użycie funkcji `bool()` w Pythonie. #### Python `bool(x)` zwraca wartość boolean dla `x` zgodnie z regułami truthiness. Typowe scenariusze: - jawna konwersja wartości do `True/False`; - czytelne warunki; - budowanie filtrów. ```python bool("text") # True bool("") # False bool(0) # False ``` **W skrócie:** - `bool()` ujednolica sprawdzenie „puste/niepuste”. - Opiera się na wbudowanych regułach truthy/falsy. - Jest przydatne w walidacji i logice warunkowej.
46. Jaka jest różnica między `list` a `tuple`? #### Python Główna różnica: `list` jest mutable, a `tuple` immutable. Praktyczne konsekwencje: - `list` nadaje się do danych, które się zmieniają; - `tuple` nadaje się do stałych rekordów; - `tuple` można używać jako klucza słownika, jeśli jego elementy są hashowalne. ```python coords: tuple[float, float] = (50.45, 30.52) queue: list[str] = ["task-1", "task-2"] ``` **W skrócie:** - `list` służy do zmiennych kolekcji. - `tuple` służy do niezmiennych struktur danych. - Wybór wpływa na bezpieczeństwo API i użycie w `dict/set`.
47. Jak można utworzyć `tuple`? #### Python Podstawowe sposoby: ```python t1 = (1, 2, 3) t2 = 1, 2, 3 t3 = tuple([1, 2, 3]) single = (42,) # ważny przecinek empty = () ``` Dla jednego elementu przecinek jest obowiązkowy, inaczej to tylko wyrażenie w nawiasach. **W skrócie:** - `tuple` tworzy się przez literał albo `tuple(iterable)`. - `single = (x,)` to poprawny jednoelementowy tuple. - Pusty tuple: `()`.
48. Jaka jest różnica między metodą `reverse` a slicingiem `[::-1]` przy odwracaniu listy? #### Python `list.reverse()` zmienia istniejącą listę in-place i zwraca `None`. `lst[::-1]` tworzy nową odwróconą listę, czyli kopię. ```python values = [1, 2, 3] values.reverse() # values -> [3, 2, 1] other = values[::-1] # nowa lista ``` **W skrócie:** - `reverse()` zmienia oryginał. - `[::-1]` zwraca nowy obiekt. - Wybór zależy od potrzeby zachowania danych wejściowych.
49. Wyjaśnij przeznaczenie i użycie metody `sort` dla list. Jak posortować listę w porządku malejącym? #### Python `list.sort()` sortuje listę in-place. Obsługuje parametry: - `key` — funkcja klucza sortowania; - `reverse=True` — porządek malejący. ```python nums = [5, 1, 7] nums.sort(reverse=True) # [7, 5, 1] ``` Jeśli potrzebna jest nowa, posortowana kopia, użyj `sorted(iterable)`. **W skrócie:** - `sort()` zmienia listę na miejscu. - Dla porządku malejącego użyj `reverse=True`. - `sorted()` jest wygodne, gdy trzeba zachować oryginał.
50. Jaka jest różnica między metodą `copy` a bezpośrednim przypisaniem jednej listy do drugiej? Dlaczego czasem ważne jest użycie `copy`? #### Python Przypisanie kopiuje tylko referencję: ```python a = [1, 2] b = a b.append(3) # a też się zmieni ``` `a.copy()` tworzy nową, płytką listę: ```python a = [1, 2] b = a.copy() b.append(3) # a się nie zmieni ``` Dla struktur zagnieżdżonych może być potrzebne `copy.deepcopy`. **W skrócie:** - `=` nie kopiuje danych, tylko współdzieli jeden obiekt między zmiennymi. - `copy()` izoluje zmiany na poziomie listy zewnętrznej. - Dla obiektów zagnieżdżonych używaj `deepcopy`.
51. Co robi metoda `pop` w liście? Czym różni się jej zachowanie, jeśli podać indeks, a jeśli nie? #### Python `pop()` usuwa i zwraca element z listy. - `pop()` bez argumentów usuwa ostatni element; - `pop(i)` usuwa element o indeksie `i`. ```python items = ["a", "b", "c"] last = items.pop() # "c" first = items.pop(0) # "a" ``` Błędny indeks powoduje `IndexError`. **W skrócie:** - `pop` łączy usunięcie elementu z jego zwróceniem. - Bez indeksu działa na końcu listy. - Z indeksem usuwa konkretną pozycję.
52. Jak połączyć dwie listy w Pythonie za pomocą operatora `+` i metody `extend`? Jaka jest kluczowa różnica między tymi dwoma sposobami? #### Python `a + b` tworzy **nową** listę, a `a.extend(b)` modyfikuje listę `a` **in-place**. ```python a = [1, 2] b = [3, 4] c = a + b # [1, 2, 3, 4], a się nie zmieniło a.extend(b) # a -> [1, 2, 3, 4] ``` **W skrócie:** - `+` zwraca nowy obiekt. - `extend()` mutuje istniejącą listę. - Wybór zależy od tego, czy trzeba zachować oryginał.
53. Do czego służą funkcje `min`, `max`, `sum`, `all`, `any` w kontekście list? #### Python To podstawowe agregatory dla iterowalnych kolekcji: - `min()` / `max()` — minimum i maksimum; - `sum()` — suma liczb; - `all()` — `True`, jeśli wszystkie elementy są truthy; - `any()` — `True`, jeśli przynajmniej jeden element jest truthy. ```python nums = [3, 10, 1] min(nums), max(nums), sum(nums) # (1, 10, 14) all([True, 1, "x"]) # True any([0, "", None, 5]) # True ``` **W skrócie:** - Funkcje zmniejszają ilość boilerplate w pętlach. - Działają z dowolnym iterable. - Dobrze łączą się z generatorami do leniwego przetwarzania.
54. Czym jest słownik (`dict`) w Pythonie i czym różni się od innych struktur danych? #### Python `dict` to tablica asocjacyjna: przechowuje pary `klucz -> wartość`. Klucze muszą być hashable, a wartości mogą mieć dowolny typ. Różnice: - dostęp odbywa się po kluczu, a nie po indeksie; - średnia złożoność wyszukiwania/wstawiania/usuwania jest bliska `O(1)`; - od Pythona 3.7+ zachowuje kolejność wstawiania kluczy. **W skrócie:** - `dict` jest optymalny do szybkiego dostępu po kluczu. - To podstawowa struktura dla konfiguracji i mapowań. - Klucze muszą być niemutowalne (hashable).
55. Jaka jest różnica między pobieraniem wartości ze słownika przez nawiasy kwadratowe `[]` a metodą `get`? #### Python `d[key]` zwraca wartość albo zgłasza `KeyError`, jeśli klucza nie ma. `d.get(key, default)` zwraca wartość albo `default` (lub `None`) bez wyjątku. ```python config = {"timeout": 30} config["timeout"] # 30 config.get("retries", 3) # 3 ``` **W skrócie:** - `[]` służy do obowiązkowych kluczy. - `get()` nadaje się do opcjonalnych pól. - `get()` zmniejsza liczbę `try/except` przy odczycie danych.
56. Opisz, jak można aktualizować i usuwać elementy ze słownika. #### Python Aktualizacja: - `d[key] = value` — wstawić/zaktualizować jeden klucz; - `d.update({...})` — aktualizacja zbiorcza. Usuwanie: - `del d[key]` — usunąć klucz (błąd, jeśli go nie ma); - `d.pop(key, default)` — usunąć i zwrócić wartość; - `d.popitem()` — usunąć ostatnią parę; - `d.clear()` — wyczyścić cały słownik. **W skrócie:** - Do upsertu nadają się `[]` i `update()`. - Do bezpiecznego usuwania częściej używa się `pop()`. - API warto dobierać zależnie od oczekiwanego zachowania przy braku klucza.
57. Do czego służą metody `keys`, `values` oraz `items` w słownikach? #### Python Te metody zwracają obiekty view słownika: - `keys()` — wszystkie klucze; - `values()` — wszystkie wartości; - `items()` — pary `(key, value)`. ```python data = {"a": 1, "b": 2} for key, value in data.items(): ... ``` Widoki są dynamiczne: odzwierciedlają aktualny stan słownika. **W skrócie:** - `keys/values/items` są potrzebne do iteracji i sprawdzeń. - `items()` jest najwygodniejsze do pętli z kluczem i wartością. - To nie są kopie, tylko "żywe" reprezentacje danych.
58. Jak `dict` działa w Pythonie pod maską? #### Python `dict` jest zaimplementowany jako hash table z optymalizacjami pamięci i szybkiego dostępu. Klucz jest haszowany, na podstawie hasza wybierana jest komórka, a kolizje są rozwiązywane wewnętrznym algorytmem probing. Praktyczne konsekwencje: - średni czas dostępu jest bliski `O(1)`; - jakość `__hash__` i `__eq__` wpływa na zachowanie; - obiektów mutable nie można używać jako kluczy. **W skrócie:** - `dict` to wysokowydajna struktura hashująca. - Szybkość osiąga dzięki haszowaniu. - Klucze muszą być hashable i stabilne.
59. Czym jest hash function? #### Python Hash function przekształca obiekt w liczbę całkowitą (hash), która jest używana do szybkiego umieszczania/wyszukiwania w `dict` i `set`. Warunki poprawności: - jeśli `a == b`, to `hash(a) == hash(b)`; - wartość hasza musi być stabilna przez cały czas życia obiektu. **W skrócie:** - Funkcja haszująca jest podstawą szybkiego działania `dict/set`. - Nie gwarantuje unikalności, bo kolizje są możliwe. - Dla klas custom ważna jest spójność `__eq__` i `__hash__`.
60. Czym jest `set` w Pythonie i czym różni się od innych struktur danych? #### Python `set` to nieuporządkowana kolekcja **unikalnych** elementów. Różnice: - automatycznie usuwa duplikaty; - oferuje szybkie operacje sprawdzania przynależności (`x in s`); - wspiera operacje zbiorowe: union/intersection/difference. **W skrócie:** - `set` jest optymalny do zapewniania unikalności i membership-check. - Kolejność elementów nie jest gwarantowana. - Elementy muszą być hashable.
61. Jak utworzyć `set` w Pythonie i jakie ograniczenia dotyczą elementów set? #### Python Tworzenie: ```python s1 = {1, 2, 3} s2 = set([1, 2, 2, 3]) # {1, 2, 3} empty = set() # nie {} ``` Ograniczenia: - elementy muszą być hashable, na przykład `int`, `str`, `tuple`; - `list`, `dict`, `set` nie można dodać bezpośrednio. **W skrócie:** - `set()` tworzy pusty zbiór. - Duplikaty są usuwane automatycznie. - Dozwolone są tylko elementy hashable.
62. Do czego służy metoda `intersection()` w Python set i czym różni się od `union()`? #### Python `intersection()` zwraca wspólne elementy zbiorów, a `union()` łączy wszystkie unikalne elementy z obu zbiorów. ```python a = {1, 2, 3} b = {3, 4} a.intersection(b) # {3} a.union(b) # {1, 2, 3, 4} ``` **W skrócie:** - `intersection` = część wspólna. - `union` = suma zbiorów, czyli wszystko unikalne. - Obie metody są podstawowe przy porównywaniu zestawów danych.
63. Jakie typy danych są immutable? #### Python Popularne typy immutable: - `int`, `float`, `bool`, `complex`; - `str`, `bytes`; - `tuple` jeśli jego elementy też są immutable; - `frozenset`; - `NoneType`. **W skrócie:** - Obiektu immutable nie można zmienić po utworzeniu. - Zamiast mutacji powstaje nowy obiekt. - Takie typy są bezpieczniejsze jako klucze `dict` i elementy `set`.
64. Jakie typy danych są mutable? #### Python Popularne typy mutable: - `list`; - `dict`; - `set`; - `bytearray`; - większość obiektów klas zdefiniowanych przez użytkownika. **W skrócie:** - Obiekty mutable zmieniają się in-place. - Mutacje mogą powodować efekty uboczne przez współdzielone referencje. - Z kopiowaniem trzeba pracować ostrożnie.
65. Dlaczego ważne jest rozumienie mutowalności podczas pracy ze słownikami albo set? #### Python `dict` i `set` opierają się na haszowaniu, dlatego ich elementy i klucze muszą być stabilne (hashable). Obiektów mutable nie da się bezpiecznie używać jako kluczy ani elementów set. Dodatkowo mutacja wartości przez współdzielone referencje często prowadzi do trudnych do przewidzenia błędów. **W skrócie:** - Mutowalność wpływa na poprawność kluczy w `dict/set`. - Współdzielone obiekty mutable często powodują efekty uboczne. - Jawne kopie i kontrola mutacji zmniejszają liczbę błędów.
66. Czym jest `None`? #### Python `None` to specjalna wartość singleton typu `NoneType`, która oznacza "brak wartości". Typowe scenariusze: - funkcja niczego jawnie nie zwraca; - opcjonalne parametry; - znacznik "dane nie są jeszcze ustawione". Sprawdzenie wykonuje się przez `is`: ```python if value is None: ... ``` **W skrócie:** - `None` oznacza brak wartości. - To singleton, więc porównuje się go przez `is`. - Często jest używany w API jako stan opcjonalny.
67. Czym jest `id` w Pythonie, jak go używać i dlaczego to ważne? #### Python `id(obj)` zwraca identyfikator obiektu, unikalny w ramach cyklu życia obiektu w bieżącym procesie. To przydaje się w diagnostyce: - czy to ten sam obiekt; - czy została utworzona kopia; - czy nastąpiła mutacja współdzielonej referencji. **W skrócie:** - `id` pomaga analizować tożsamość obiektów. - Jest przydatny przy debugowaniu kopiowania i mutacji. - Nie używa się go jako identyfikatora biznesowego.
68. Jaka jest różnica między operatorami `is` i `==`? #### Python `==` porównuje **wartości** czyli równoważność, a `is` porównuje **tożsamość**, czyli czy to dokładnie ten sam obiekt w pamięci. ```python a = [1, 2] b = [1, 2] a == b # True a is b # False ``` **Ważne o optymalizacjach (interning):** CPython buforuje małe liczby całkowite od `-5` do `256` oraz krótkie napisy na etapie kompilacji lub ładowania. Dlatego dla nich `is` może zwracać `True`, nawet jeśli zostały utworzone osobno. To jednak szczegół implementacyjny, na którym nie należy opierać logiki biznesowej. Dla `None` zawsze używaj `is`. **W skrócie:** - `==` dotyczy równości wartości. - `is` dotyczy dokładnie tego samego obiektu w pamięci. - Interning może dawać nieoczywiste `is True` dla małych `int` i `str`. - `value is None` to jedyny poprawny styl sprawdzania `None`.
69. Jak stosuje się Singleton pattern w Pythonie? Podaj przykłady obiektów typu Singleton w Pythonie. #### Python Singleton oznacza jedną globalną instancję obiektu w procesie. W Pythonie często zastępuje się go poziomem modułu, ponieważ moduły są importowane tylko raz. Przykłady singletonów w języku: - `None`; - `True` i `False`; - `Ellipsis`. W kodzie aplikacyjnym zamiast sztywnego Singletonu częściej używa się kontenera DI albo fabryk, żeby poprawić testowalność. **W skrócie:** - Python ma już wbudowane obiekty typu singleton. - Często wystarcza zakres modułu bez osobnego wzorca. - Nadużywanie Singletonu pogarsza testowalność.
70. Do czego służą operatory `break` i `continue` w pętlach Pythona? #### Python `break` przedwcześnie kończy pętlę, a `continue` pomija bieżącą iterację i przechodzi do następnej. ```python for n in range(10): if n == 5: break if n % 2 == 0: continue ``` **W skrócie:** - `break` zatrzymuje całą pętlę. - `continue` pomija tylko bieżący krok. - Dzięki nim sterowanie pętlą jest jawne i czytelne.
71. Wyjaśnij pojęcie pętli nieskończonej. W jakich przypadkach warto jej używać i jak zapewnić jej poprawne zakończenie? #### Python Pętla nieskończona to pętla bez naturalnego warunku zakończenia, na przykład `while True`. Jest używana w procesach usługowych, workerach, pollingu i logice pętli zdarzeń. Poprawne zakończenie: - wyraźny warunek `break`; - obsługa sygnałów zakończenia; - timeouty i `try/finally` do czyszczenia zasobów. ```python while True: task = queue.get() if task is None: break handle(task) ``` **W skrócie:** - `while True` jest uzasadnione w długowiecznych pętlach usługowych. - Potrzebny jest kontrolowany mechanizm zatrzymania. - Zawsze trzeba przewidzieć zwalnianie zasobów.
72. Opisz, jak działają zagnieżdżone pętle w Pythonie. Jakie problemy z wydajnością mogą się pojawić i jak ich unikać? #### Python Pętla zagnieżdżona to pętla wewnątrz innej pętli. Złożoność często rośnie do `O(n*m)` albo gorzej, co jest krytyczne przy dużych zbiorach danych. Optymalizacje: - zamieniać wyszukiwanie w listach na `set` lub `dict`; - wynosić niezmienniki poza pętlę wewnętrzną; - używać generatorów, `itertools` i wektoryzacji; - profilować "gorące" miejsca. **W skrócie:** - Zagnieżdżone pętle szybko zwiększają koszt obliczeń. - Struktury danych są często ważniejsze niż mikrooptymalizacje. - Profilowanie pokazuje, co naprawdę trzeba optymalizować.
73. Czym jest structural pattern matching (`match`/`case`)? #### Python `match/case` w Pythonie 3.10+ to mechanizm dopasowywania struktury danych do wzorców. Działa z literałami, typami, sekwencjami, słownikami i klasami. ```python def handle(message: dict[str, object]) -> str: match message: case {"type": "ping"}: return "pong" case {"type": "user", "id": int(user_id)}: return f"user:{user_id}" case _: return "unknown" ``` **W skrócie:** - `match/case` jest czytelniejsze przy złożonym rozgałęzieniu. - Pozwala jednocześnie sprawdzać kształt danych i wyciągać wartości. - Jest szczególnie przydatne przy protokołach, zdarzeniach i parsowaniu struktur.
74. W jakich przypadkach pattern matching jest lepszy niż `if`/`elif`? #### Python `match/case` jest lepszy, gdy trzeba: - sprawdzać wiele wzajemnie wykluczających się form danych; - rozpakowywać zagnieżdżone struktury; - unikać długich łańcuchów `if/elif`. `if/elif` jest lepsze dla prostych warunków logicznych i krótkiej logiki. **W skrócie:** - Dla scenariuszy strukturalnych lepszy jest `match/case`. - Dla prostych warunków wystarczy `if/elif`. - Kryterium wyboru to czytelność i łatwość utrzymania.
75. Czym jest funkcja w Pythonie? #### Python Funkcja to nazwany blok kodu typu callable, który przyjmuje argumenty, zwraca wynik i pozwala enkapsulować logikę. ```python def normalize_name(name: str) -> str: return name.strip().title() ``` Funkcje wspierają wartości domyślne, argumenty nazwane, `*args/**kwargs`, adnotacje typów i dekoratory. **W skrócie:** - Funkcja jest podstawową jednostką ponownego użycia kodu. - Tworzy wyraźny kontrakt przez parametry i wartość return. - Type hints czynią ten kontrakt bardziej jawnym.
76. Jakie istnieją typy argumentów funkcji? #### Python We współczesnym Pythonie: - positional-only (`/`); - positional-or-keyword; - keyword-only (`*`); - variadic positional (`*args`); - variadic keyword (`**kwargs`). ```python def f(a, /, b, *, c, **kwargs): ... ``` **W skrócie:** - Python daje elastyczną kontrolę nad sposobem wywołania funkcji. - `/` i `*` formalizują kontrakt API. - `*args/**kwargs` są przydatne w rozszerzalnych interfejsach.
77. Czym są argumenty pozycyjne i nazwane? #### Python Argumenty pozycyjne są przekazywane według kolejności, a nazwane (`keyword`) według nazwy parametru. ```python def connect(host: str, port: int) -> str: return f"{host}:{port}" connect("localhost", 5432) # pozycyjnie connect(host="localhost", port=5432) # nazwane ``` **W skrócie:** - Pozycyjne zależą od kolejności parametrów. - Nazwane zwiększają czytelność wywołania. - Można je łączyć z zachowaniem zasad sygnatury.
78. Czym są argumenty domyślne i jakie problemy mogą z nimi występować? #### Python Argumenty domyślne są używane, jeśli wartość nie została przekazana przy wywołaniu. Są obliczane **tylko raz** w momencie definiowania funkcji. Problem: mutable default. ```python def add_item(item: int, bucket: list[int] | None = None) -> list[int]: if bucket is None: bucket = [] bucket.append(item) return bucket ``` **W skrócie:** - Wartości domyślne są wygodne dla stabilnych danych. - Mutable default może kumulować stan między wywołaniami. - Bezpieczny wzorzec to `None` + inicjalizacja wewnątrz funkcji.
79. Wyjaśnij przeznaczenie i użycie `*args` oraz `**kwargs` w funkcjach Pythona. Czym się różnią? #### Python `*args` zbiera dodatkowe argumenty pozycyjne do `tuple`. `**kwargs` zbiera dodatkowe argumenty nazwane do `dict`. ```python def log_event(event: str, *args: object, **kwargs: object) -> None: ... ``` Zastosowania: wrappery, adaptery API, dekoratory i przekazywanie parametrów dalej. **W skrócie:** - `*args` = dodatkowe argumenty pozycyjne. - `**kwargs` = dodatkowe argumenty nazwane. - Dają funkcjom elastyczność, ale wymagają jasnej walidacji.
80. Jak zdefiniować funkcję z type annotations w Pythonie? Podaj przykład i wyjaśnij zalety tego podejścia. #### Python Typy zapisuje się w sygnaturze parametrów i wartości return. ```python def process_users(users: list[dict[str, object]]) -> list[str]: return [str(user["name"]) for user in users if bool(user.get("active"))] ``` Zalety: - lepszy DX, czyli autocomplete i nawigacja; - statyczne sprawdzanie w CI; - jawny kontrakt dla innych programistów. **W skrócie:** - Adnotacje typów dokumentują API. - Zmniejszają ryzyko błędów integracyjnych. - Najwięcej dają w średnich i dużych bazach kodu.
81. Czym są funkcje lambda? #### Python `lambda` to anonimowa funkcja jedno-wyrażeniowa. Zwykle jest używana do krótkich callbacków w `sorted`, `map`, `filter`. ```python users = [{"name": "Ada"}, {"name": "Bob"}] users_sorted = sorted(users, key=lambda u: u["name"]) ``` Dla bardziej złożonej logiki lepsza jest zwykła funkcja `def`. **W skrócie:** - `lambda` jest wygodna do krótkich lokalnych wyrażeń. - Jest ograniczona do jednego wyrażenia. - Dla czytelności bardziej złożony kod lepiej wynieść do `def`.
82. Jaki jest zakres widoczności zmiennych w funkcji? #### Python Python używa reguły LEGB do wyszukiwania nazw: - `L`ocal; - `E`nclosing, czyli funkcje zewnętrzne; - `G`lobal, czyli moduł; - `B`uiltins. Wewnątrz funkcji przypisanie tworzy zmienną lokalną, jeśli nie użyto `global` albo `nonlocal`. **W skrócie:** - Scope określa, gdzie nazwa jest dostępna i może być zmieniana. - LEGB wyjaśnia kolejność wyszukiwania zmiennych. - Błędne rozumienie zasięgu często prowadzi do `UnboundLocalError`.
83. Czym są zmienne lokalne i globalne w Pythonie? #### Python Zmienne lokalne istnieją w ciele funkcji. Zmienne globalne są zdefiniowane na poziomie modułu. Aby zmienić zmienną globalną z poziomu funkcji, potrzebny jest `global`, ale zwykle warto tego unikać przez niejawne zależności. **W skrócie:** - Zmienne lokalne są bezpieczniejsze dla utrzymania i testowania. - Globalne upraszczają dostęp, ale utrudniają kontrolę stanu. - Lepiej przekazywać zależności przez parametry.
84. Jaka jest różnica między zmiennymi lokalnymi a `nonlocal` w Pythonie? #### Python `nonlocal` jest używane w funkcji zagnieżdżonej do zmiany zmiennej z najbliższego zewnętrznego zasięgu, czyli nie globalnego. ```python from collections.abc import Callable def counter() -> Callable: value = 0 def inc() -> int: nonlocal value value += 1 return value return inc ``` **W skrócie:** - Zmienna lokalna należy do bieżącej funkcji. - `nonlocal` zmienia stan funkcji zewnętrznej. - To kluczowy mechanizm dla closure ze stanem.
85. Czym jest unpacking w Pythonie i jak stosuje się go przy przypisaniu? #### Python Unpacking to rozkładanie elementów sekwencji lub struktury na osobne zmienne. ```python x, y = (10, 20) first, *middle, last = [1, 2, 3, 4] ``` Działa też ze słownikami w `match/case`, przy wywołaniach funkcji i w pętlach. **W skrócie:** - Unpacking sprawia, że kod jest bardziej zwięzły i czytelny. - Wspiera "gwiazdkowe" przechwycenie pozostałych wartości. - Często jest używany przy parsowaniu struktur danych.
86. Wyjaśnij pojęcie packing wartości w Pythonie i podaj przykłady. #### Python Packing to zbieranie kilku wartości do jednej struktury, na przykład `tuple`, `list`, `dict`. ```python point = 10, 20 # tuple packing def collect(*args: int) -> tuple[int, ...]: return args ``` `*args` i `**kwargs` to typowy przykład packingu argumentów. **W skrócie:** - Packing zbiera wiele wartości do jednego kontenera. - Najczęściej jest używany w sygnaturach funkcji. - Dobrze łączy się z unpackingiem po stronie wywołania.
87. Do czego używa się operatora `*` przy packingu i unpackingu? #### Python `*` w parametrach funkcji pakuje argumenty pozycyjne do `*args`, a przy wywołaniu rozpakowuje iterable do argumentów pozycyjnych. ```python def add(a: int, b: int) -> int: return a + b nums = [2, 3] add(*nums) # 5 ``` `*` jest też używane w przypisaniu do przechwycenia "reszty" elementów. **W skrócie:** - `*` to uniwersalny operator do pracy z varargs. - W sygnaturze pakuje, przy wywołaniu rozpakowuje. - Zmniejsza ilość szablonowego kodu przy przekazywaniu danych.
88. Czym jest closure i jaki ma związek z decoratorami? #### Python Closure to funkcja wewnętrzna, która "pamięta" zmienne z zewnętrznego zakresu nawet po zakończeniu działania funkcji zewnętrznej. Decorator zwykle implementuje się właśnie przez closure: wrapper przechowuje odwołanie do oryginalnej funkcji i dodatkowych parametrów. **W skrócie:** - Closure to funkcja plus przechwycony kontekst. - Decorator jest często praktycznym zastosowaniem closure. - Daje możliwość dodania zachowania bez zmiany ciała funkcji.
89. Czym jest decorator w Pythonie i jak działa? #### Python Decorator to obiekt callable, który przyjmuje funkcję albo klasę i zwraca zmodyfikowaną wersję, czyli wrapper. ```python from functools import wraps def log_calls(func): @wraps(func) def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper ``` Zastosowania: logowanie, cache'owanie, autoryzacja, retry i metryki. **W skrócie:** - Decorator dodaje zachowanie cross-cutting. - Działa przez opakowanie callable. - Pozwala nie duplikować technicznej logiki w kodzie biznesowym.
90. Czy można używać kilku decoratorów dla jednej funkcji? #### Python Tak, można układać kilka decoratorów w stos. Są stosowane od dołu do góry, czyli ten bliżej `def` opakowuje funkcję jako pierwszy. ```python @decorator_a @decorator_b def handler() -> None: ... ``` Równoważny zapis: `handler = decorator_a(decorator_b(handler))`. **W skrócie:** - Kilka decoratorów jest dopuszczalne i powszechne. - Kolejność zastosowania ma znaczenie. - Stos decoratorów warto dokumentować dla przejrzystości.
91. Opisz możliwy problem z kolejnością decoratorów przy ich stosowaniu do funkcji. #### Python Nieprawidłowa kolejność może zmienić semantykę. Na przykład cache'owanie przed sprawdzeniem dostępu może zachować niepożądany wynik albo ominąć oczekiwaną logikę. Typowe ryzyka: - logowanie widzi już zmienione argumenty; - retry opakowują nie ten wyjątek; - cache jest nakładany przed lub po walidacji w złym miejscu. **W skrócie:** - Kolejność decoratorów wpływa na zachowanie funkcji. - To częsta przyczyna ukrytych błędów. - Dla krytycznych łańcuchów potrzebne są testy kolejności wykonania.
92. Czy można utworzyć decorator za pomocą klasy? #### Python Tak. Klasa-decorator implementuje `__call__`, aby instancja zachowywała się jak funkcja. ```python class CallCounter: def __init__(self, func): self.func = func self.calls = 0 def __call__(self, *args, **kwargs): self.calls += 1 return self.func(*args, **kwargs) ``` **W skrócie:** - Decorator można zaimplementować nie tylko jako funkcję, ale też jako klasę. - Klasa jest wygodna, gdy potrzebny jest wewnętrzny stan. - Kluczowy mechanizm to `__call__`.
93. Jak zdefiniować decorator przyjmujący parametry? #### Python Potrzebna jest trójpoziomowa struktura: fabryka dekoratora -> decorator -> wrapper. ```python from functools import wraps def retry(times: int): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): for _ in range(times - 1): try: return func(*args, **kwargs) except Exception: pass return func(*args, **kwargs) return wrapper return decorator ``` **W skrócie:** - Parametryzowany decorator to funkcja, która zwraca decorator. - Do zachowania parametrów często używa się closure. - To podejście jest wygodne przy konfigurowalnym zachowaniu.
94. Do czego używa się `functools.wraps` w funkcjach-decoratorach? #### Python `functools.wraps` kopiuje metadane oryginalnej funkcji do wrappera: nazwę, docstring, moduł oraz `__wrapped__`. To ważne dla: - poprawnego debugowania i logów; - introspekcji i dokumentacji; - zgodności z narzędziami, które odczytują sygnaturę. **W skrócie:** - `wraps` zachowuje "tożsamość" oryginalnej funkcji. - Bez niego dekorowane funkcje tracą przydatne metadane. - To best practice dla wszystkich decoratorów opartych na wrapperze.
95. Jak działają dict comprehension, list comprehension i set comprehension? #### Python Comprehension tworzy kolekcję na podstawie wyrażenia i pętli, opcjonalnie z filtrem. ```python squares = [x * x for x in range(6)] mapping = {x: x * x for x in range(6)} unique = {x % 3 for x in range(10)} ``` Format: - list: `[expr for x in it if cond]` - set: `{expr for x in it if cond}` - dict: `{k_expr: v_expr for x in it if cond}` **W skrócie:** - Comprehension w zwięzły sposób wyraża transformację danych. - Działa dla `list`, `set` i `dict`. - Daje czystszy kod niż ręczne dodawanie elementów w pętli.
96. Jakie są zalety używania list comprehension w porównaniu ze zwykłymi pętlami? #### Python Zalety: - krótszy i bardziej deklaratywny kod; - mniej zmiennych pomocniczych; - zwykle trochę lepsza wydajność w CPythonie; - mniejsze ryzyko, że zapomnisz o `append`. Wada: przy bardzo złożonej logice comprehension pogarsza czytelność. **W skrócie:** - List comprehension dobrze nadaje się do prostych transformacji. - Często jest szybsze i czystsze niż ręczna pętla. - Dla złożonych gałęzi lepszy jest zwykły `for`.
97. Czy możesz podać przykład zagnieżdżonej list comprehension? #### Python Przykład spłaszczenia macierzy: ```python matrix = [[1, 2], [3, 4], [5, 6]] flat = [item for row in matrix for item in row] # [1, 2, 3, 4, 5, 6] ``` Przykład z warunkiem: ```python pairs = [(x, y) for x in range(3) for y in range(3) if x != y] ``` **W skrócie:** - Zagnieżdżona comprehension to kilka `for` w jednym wyrażeniu. - Kolejność `for` odpowiada zagnieżdżonym pętlom. - Używaj jej wtedy, gdy wyrażenie pozostaje czytelne.
98. Co jest szybsze w Pythonie: list comprehension czy tworzenie listy za pomocą pętli? #### Python W typowych scenariuszach list comprehension jest trochę szybsze niż pętla z `append`, bo ma zoptymalizowany bajtkod i mniej narzutu. Ważne: realny zysk zależy od samej operacji, dlatego w krytycznych miejscach warto mierzyć wydajność za pomocą `timeit` lub `pyperf`. **W skrócie:** - Często szybsze jest list comprehension. - Różnica może być niewielka. - W rozwiązaniach produkcyjnych trzeba opierać się na pomiarach.
99. Czym jest iterator w Pythonie? #### Python Iterator to obiekt, który zwraca elementy sekwencyjnie i pamięta bieżący stan. Implementuje protokół: - `__iter__()` zwraca siebie; - `__next__()` zwraca następny element albo zgłasza `StopIteration`. **W skrócie:** - Iterator daje dostęp element po elemencie bez pełnego wczytywania danych. - To podstawa dla `for`, generatorów i leniwego przetwarzania. - Po wyczerpaniu iterator nie "przewija się" sam.
100. Jak utworzyć iterator z obiektu iterowalnego za pomocą funkcji `iter()`? #### Python Wywołaj `iter(iterable)`, aby otrzymać iterator. ```python items = [10, 20, 30] it = iter(items) ``` Potem wartości odczytuje się przez `next(it)`. **W skrócie:** - `iter()` zamienia iterable na iterator. - To jawny sposób ręcznego sterowania iteracją. - Używa się go w niskopoziomowym przetwarzaniu strumienia danych.
101. Do czego służy funkcja `next()` przy pracy z iteratorami? #### Python `next(iterator[, default])` zwraca następny element iteratora. Gdy elementy się skończą, zgłasza `StopIteration` albo zwraca `default`, jeśli został podany. ```python it = iter([1, 2]) next(it) # 1 next(it) # 2 next(it, None) # None ``` **W skrócie:** - `next()` daje ręczną kontrolę nad krokiem iteracji. - Bez `default` koniec strumienia oznacza `StopIteration`. - Z `default` można wygodnie i bezpiecznie czytać strumień.
102. Czy można zamiennie używać metod `__next__()` i `__iter__()` z funkcjami `next()` oraz `iter()`? #### Python Tak, ale z uwzględnieniem protokołu: - `iter(obj)` wywołuje `obj.__iter__()`; - `next(it)` wywołuje `it.__next__()`. Funkcje są więc standardowym interfejsem do metod dunder i zwykle używa się ich zamiast bezpośrednich wywołań. **W skrócie:** - `iter()` odpowiada `__iter__()`. - `next()` odpowiada `__next__()`. - W kodzie aplikacyjnym lepiej wywoływać funkcje wbudowane.
103. Jaka jest rola `StopIteration` w projektowaniu iteratorów i kiedy zwykle się pojawia? #### Python `StopIteration` sygnalizuje, że iterator został wyczerpany. Pętla `for` automatycznie go przechwytuje i kończy iterację. Zwykle pojawia się: - przy wywołaniu `next(it)` po ostatnim elemencie; - we własnych iteratorach, gdy dane się skończyły. **W skrócie:** - `StopIteration` to normalny koniec strumienia. - Nie trzeba go logować jako "błędu" w normalnym przepływie. - We własnych iteratorach trzeba zgłaszać go poprawnie.
104. Czym jest generator i czym różni się od iteratora albo zwykłej funkcji? #### Python Generator to specjalny iterator tworzony przez funkcję z `yield`. Zwraca wartości po jednej i zachowuje wewnętrzny stan między wywołaniami. Różnice: - od zwykłej funkcji: nie kończy się jednym `return`, tylko działa w trybie "pauza/wznowienie"; - od ręcznego iteratora: ma prostszą implementację bez jawnej klasy z `__next__`. **W skrócie:** - Generator to najwygodniejszy sposób leniwej iteracji. - Wymaga mniej kodu niż własna klasa iteratora. - Jest szczególnie przydatny dla dużych strumieni danych.
105. Jak utworzyć funkcję generatora? #### Python Trzeba zdefiniować funkcję z `yield`. ```python def countdown(start: int): current = start while current > 0: yield current current -= 1 ``` Wywołanie `countdown(3)` zwraca obiekt generatora, po którym można iterować. **W skrócie:** - Obecność `yield` sprawia, że funkcja staje się generatorem. - Generator zwraca wartości etapami. - Stan funkcji jest zachowywany między iteracjami.
106. Jak słowo kluczowe `yield` zapewnia działanie generatorów i dlaczego oszczędzają one pamięć? #### Python `yield` zwraca kolejną wartość i "zamraża" kontekst funkcji, czyli zmienne lokalne oraz miejsce wykonania. Następne `next()` wznawia działanie od tego punktu. Oszczędność pamięci wynika z tego, że dane nie są tworzone w całości z góry, tylko obliczane na żądanie. **W skrócie:** - `yield` realizuje mechanizm pauzy i wznowienia wykonania. - Generator wspiera leniwe obliczanie. - To zmniejsza zużycie pamięci dla dużych zbiorów danych.
107. Jaka jest różnica między `return` a `yield`? #### Python `return` kończy funkcję i zwraca jedną końcową wartość. `yield` zwraca wartość pośrednią i zachowuje stan do dalszego wznowienia. W generatorze `return` oznacza koniec iteracji, czyli `StopIteration`. **W skrócie:** - `return` oznacza zakończenie funkcji. - `yield` oznacza etapowe zwracanie wartości. - `yield` jest używane przy przetwarzaniu strumieniowym.
108. Czym jest Object-Oriented Programming (OOP) i jakie są jego główne zasady w Pythonie? #### Python OOP to podejście, w którym dane i zachowanie są połączone w obiektach. Główne zasady: - enkapsulacja; - dziedziczenie; - polimorfizm; - abstrakcja. W Pythonie OOP zwykle łączy się z kompozycją i duck typing. **W skrócie:** - OOP strukturyzuje domenę przez klasy i obiekty. - Python wspiera OOP elastycznie, bez nadmiaru szablonowego kodu. - W praktyce kompozycja często bywa lepsza niż głębokie dziedziczenie.
109. Czym jest `class` w Pythonie? #### Python `class` to szablon do tworzenia obiektów z atrybutami i metodami. ```python class User: def __init__(self, name: str) -> None: self.name = name ``` Klasa określa strukturę i zachowanie przyszłych instancji. **W skrócie:** - Klasa opisuje dane i operacje na nich. - Na podstawie klasy tworzone są obiekty, czyli instancje. - To podstawowa jednostka modelowania w OOP.
110. Jak utworzyć obiekt w Pythonie? #### Python Obiekt tworzy się przez wywołanie klasy: ```python class User: def __init__(self, name: str) -> None: self.name = name user = User("Ada") ``` Podczas tworzenia wykonywane jest `__init__`, aby zainicjalizować stan. **W skrócie:** - Obiekt to instancja klasy. - Tworzenie wygląda tak: `instance = ClassName(...)`. - `__init__` ustawia początkowe atrybuty.
111. Czym są obiekty i atrybuty? #### Python Obiekt to konkretna instancja typu albo klasy. Atrybut to powiązana z obiektem para nazwa-wartość, czyli dane albo metoda. ```python user.name # atrybut-dane user.save() # atrybut-metoda ``` **W skrócie:** - Obiekt przechowuje stan i zachowanie. - Atrybuty opisują ten stan i zachowanie. - Dostęp do atrybutów odbywa się przez notację kropkową.
112. Jaką rolę pełni metoda `__init__()` w klasie? #### Python `__init__` to inicjalizator instancji: jest wywoływany po utworzeniu obiektu i ustawia stan początkowy. ```python class Account: def __init__(self, owner: str, balance: float = 0.0) -> None: self.owner = owner self.balance = balance ``` **W skrócie:** - `__init__` ustawia początkowe atrybuty obiektu. - Działa jako punkt wejścia konfiguracji instancji. - Nie tworzy obiektu, tylko go inicjalizuje.
113. Do czego służy parametr `self` w metodach klas Pythona? #### Python `self` to referencja do bieżącej instancji. Przez `self` metoda odczytuje i zmienia atrybuty instancji. ```python def deposit(self, amount: float) -> None: self.balance += amount ``` Nazwa `self` nie jest zarezerwowana składniowo, ale jest powszechnie przyjętym standardem. **W skrócie:** - `self` wiąże metodę z konkretnym obiektem. - Przez `self` dostępne są dane instancji. - To obowiązkowy pierwszy parametr metody instancji.
114. Jak definiować metody w klasie? #### Python Metody definiuje się jako funkcje wewnątrz `class`. ```python class Calculator: def add(self, a: int, b: int) -> int: return a + b ``` Typowe rodzaje to metody instancji (`self`), klasy (`@classmethod`, `cls`) i statyczne (`@staticmethod`, bez `self/cls`). **W skrócie:** - Metoda to funkcja wewnątrz ciała klasy. - Typ metody określają dekorator i sygnatura. - Najczęściej używana jest metoda instancji.
115. Wyjaśnij koncepcję "wszystko jest obiektem" w Pythonie i podaj przykłady. #### Python W Pythonie prawie wszystko jest obiektem: liczby, napisy, funkcje, klasy i moduły. Dlatego wszystko ma typ, atrybuty i zachowanie. ```python type(10) # <class 'int'> type(len) # <class 'builtin_function_or_method'> type(str) # <class 'type'> ``` **W skrócie:** - Jednolity model obiektowy upraszcza język. - Funkcje i klasy też są obiektami pierwszej kategorii. - To sprawia, że Python jest elastyczny w metaprogramowaniu.
116. Podaj przykład klasy z metodami, które wykonują obliczenia na podstawie atrybutów. #### Python ```python class Rectangle: def __init__(self, width: float, height: float) -> None: self.width = width self.height = height def area(self) -> float: return self.width * self.height def perimeter(self) -> float: return 2 * (self.width + self.height) ``` **W skrócie:** - Metody mogą obliczać wartości na podstawie atrybutów instancji. - To enkapsuluje logikę domenową w obiekcie. - API klasy staje się samoopisowe.
117. Opisz sytuację, w której może być potrzebne użycie kilku klas w programie Pythona. #### Python Gdy domena ma kilka odpowiedzialności, rozdziela się je między klasy. Na przykład w systemie e-commerce: `Order`, `OrderItem`, `PaymentService`, `InventoryService`. To daje: - wyraźny podział odpowiedzialności; - słabsze sprzężenie; - łatwiejszą wymianę i testowanie komponentów. **W skrócie:** - Kilka klas jest potrzebnych do modelowania złożonej domeny. - Podział odpowiedzialności zwiększa utrzymywalność. - Kompozycja klas zwykle jest lepsza niż "obiekt-bóg".
118. Jaka jest różnica między metodą instancji, metodą klasy i metodą statyczną? #### Python - Metoda instancji ma `self` i działa na konkretnej instancji. - Metoda klasy ma `cls` i działa na klasie jako całości. - Metoda statyczna nie ma `self/cls`; to funkcja pomocnicza w przestrzeni nazw klasy. **W skrócie:** - Metoda instancji to logika instancji. - Metoda klasy to logika klasy i alternatywne konstruktory. - Metoda statyczna to logika pomocnicza bez dostępu do stanu.
119. Czym jest `@classmethod` w Pythonie i czym różni się od zwykłych metod? #### Python `@classmethod` przekazuje jako pierwszy argument klasę `cls`, a nie instancję. Często używa się go do metod fabrykujących. ```python class User: def __init__(self, name: str) -> None: self.name = name @classmethod def from_email(cls, email: str) -> User: return cls(email.split("@")[0]) ``` **W skrócie:** - `classmethod` działa na poziomie klasy. - Jest wygodny dla alternatywnych konstruktorów. - Nie wymaga już utworzonej instancji.
120. Czym jest `@staticmethod` w klasach Pythona i kiedy warto go stosować? #### Python `@staticmethod` definiuje metodę bez automatycznego `self` ani `cls`. Logicznie należy do klasy, ale nie zależy od jej stanu. ```python class Math: @staticmethod def clamp(value: int, min_v: int, max_v: int) -> int: return max(min_v, min(value, max_v)) ``` **W skrócie:** - `staticmethod` to funkcja w namespace klasy. - Używaj go do logiki pomocniczej bez dostępu do atrybutów. - Nie nadaje się tam, gdzie potrzebny jest stan instancji albo klasy.
121. Jaka jest różnica między `@classmethod` a `@staticmethod` w klasach Pythona? #### Python Różnica dotyczy pierwszego argumentu i poziomu dostępu: - `@classmethod` otrzymuje `cls` i może pracować ze stanem klasy; - `@staticmethod` nie otrzymuje nic automatycznie. Metoda klasowa częściej służy do metod fabrykujących i polimorficznych konstruktorów, a metoda statyczna do funkcji pomocniczych. **W skrócie:** - Metoda klasowa "wie" o klasie. - Metoda statyczna jest odizolowana od stanu klasy i instancji. - Wybór zależy od tego, czy potrzebny jest dostęp do `cls`.
122. Czym są atrybuty instancji w klasach Pythona i czym różnią się od atrybutów klasowych? #### Python Atrybuty instancji należą do konkretnego obiektu, na przykład `self.x`. Atrybuty klasowe należą do klasy i są współdzielone przez wszystkie instancje. ```python class User: role = "member" # atrybut klasowy def __init__(self, name: str) -> None: self.name = name # atrybut instancji ``` **W skrócie:** - Atrybuty instancji przechowują indywidualny stan. - Atrybuty klasowe przechowują wspólną konfigurację. - Zmiany atrybutów klasowych wpływają na wszystkie instancje.
123. Czym jest `__slots__` w Pythonie? #### Python `__slots__` ogranicza zestaw dozwolonych atrybutów w klasie i może zmniejszyć zużycie pamięci, usuwając `__dict__` z instancji. ```python class Point: __slots__ = ("x", "y") def __init__(self, x: int, y: int) -> None: self.x = x self.y = y ``` **Niuanse użycia:** - **Oszczędność pamięci:** obiekty zajmują znacznie mniej miejsca, bo atrybuty są przechowywane w stałej strukturze zamiast w tablicy haszującej `__dict__`. - **Szybkość:** dostęp do atrybutów w `__slots__` bywa zwykle trochę szybszy. - **Brak `__dict__`:** nie da się dynamicznie dodawać nowych atrybutów, których nie ma na liście `__slots__`, chyba że doda się tam `"__dict__"`. - **Słabe referencje:** jeśli chcesz używać `weakref`, trzeba jawnie dodać `"__weakref__"` do `__slots__`. **W skrócie:** - `__slots__` jest przydatny dla milionów lekkich obiektów, na przykład węzłów grafu. - Domyślnie usuwa `__dict__` i `__weakref__`. - Zmniejsza elastyczność na rzecz wydajności i kontroli.
124. Czym są magic methods, czyli metody dunder, w klasach Pythona i dlaczego nazywa się je "magicznymi"? #### Python Metody dunder, takie jak `__init__`, `__str__`, `__len__`, `__eq__`, to specjalne punkty zaczepienia, które Python wywołuje automatycznie w odpowiedzi na operatory i funkcje wbudowane. Nazywa się je "magicznymi", ponieważ integrują klasę z zachowaniem samego języka. **W skrócie:** - Metody dunder definiują protokołowe zachowanie obiektu. - Pozwalają klasom zachowywać się "jak typy wbudowane". - Używaj ich tylko wtedy, gdy istnieje wyraźna potrzeba semantyczna.
125. Do czego służy metoda `__del__`? #### Python `__del__` to finalizator, który może zostać wywołany przed zniszczeniem obiektu przez GC. Jego działanie nie jest deterministyczne, dlatego do zarządzania zasobami lepiej używać menedżerów kontekstu, czyli `with`, oraz jawnego zamykania. **W skrócie:** - `__del__` nie gwarantuje terminowego wykonania. - Nie opieraj krytycznego czyszczenia wyłącznie na nim. - Zalecane podejście to `with` lub `try/finally`.
126. Podaj przykład użycia magicznej metody `__str__` do zdefiniowania tekstowej reprezentacji własnej klasy w Pythonie. #### Python ```python class User: def __init__(self, name: str, active: bool) -> None: self.name = name self.active = active def __str__(self) -> str: status = "active" if self.active else "inactive" return f"User(name={self.name}, status={status})" ``` `str(user)` i `print(user)` użyją `__str__`. **W skrócie:** - `__str__` daje reprezentację obiektu zrozumiałą dla człowieka. - Jest przydatny w logach i wyjściu CLI. - Powinien być krótki i czytelny.
127. Do czego używa się `__str__` i `__repr__`? #### Python `__str__` jest skierowany do końcowego odbiorcy. `__repr__` jest skierowany do programisty i debugowania, dlatego najlepiej, by był jednoznaczny. `print(obj)` zwykle używa `__str__`, a REPL oraz `repr(obj)` używają `__repr__`. **W skrócie:** - `__str__` służy do przyjaznego wyjścia. - `__repr__` służy do technicznej reprezentacji. - Dobrą praktyką jest posiadanie obu, jeśli klasa jest domenowa.
128. Jak działa przeciążanie operatorów w Pythonie i dlaczego jest to przydatne? #### Python Przeciążanie operatorów polega na implementacji metod dunder operatorów, takich jak `__add__`, `__sub__`, `__eq__`, aby obiekty własnej klasy obsługiwały operatory. ```python class Vector2: def __init__(self, x: float, y: float) -> None: self.x = x self.y = y def __add__(self, other: "Vector2") -> "Vector2": return Vector2(self.x + other.x, self.y + other.y) ``` **W skrócie:** - Daje naturalną składnię dla typów domenowych. - Zwiększa wyrazistość API. - Ważne jest zachowanie matematycznie oczekiwanej semantyki.
129. Czym jest dziedziczenie? #### Python Dziedziczenie pozwala utworzyć klasę pochodną, która odziedzicza atrybuty i metody klasy bazowej oraz może rozszerzać albo nadpisywać jej zachowanie. **W skrócie:** - Dziedziczenie sprzyja ponownemu użyciu kodu. - Klasa pochodna może nadpisywać metody klasy bazowej. - Nadmierna hierarchia utrudnia utrzymanie, więc często lepsza jest kompozycja.
130. Czym jest pojedyncze dziedziczenie w Pythonie? #### Python Pojedyncze dziedziczenie oznacza, że klasa ma tylko jednego bezpośredniego rodzica. ```python class Animal: ... class Dog(Animal): ... ``` To najprostsza i zwykle najbardziej czytelna forma dziedziczenia. **W skrócie:** - Jedna klasa pochodna oznacza jedną klasę bazową. - To prosty model rozwiązywania metod. - Często wystarcza dla większości modeli biznesowych.
131. Jak zaimplementować dziedziczenie w klasach Pythona i jaka składnia jest do tego używana? #### Python Składnia: `class Child(Base):`. ```python class Base: def greet(self) -> str: return "hello" class Child(Base): def greet(self) -> str: return "hi" ``` Jeśli trzeba wywołać logikę klasy bazowej, użyj `super()`. **W skrócie:** - Dziedziczenie zapisuje się w nawiasach po nazwie klasy. - Klasa pochodna otrzymuje API klasy bazowej. - Nadpisywanie pozwala dostosować zachowanie.
132. Jak uzyskać dostęp do składowych klasy bazowej w klasie pochodnej? #### Python Dostęp jest możliwy bezpośrednio przez odziedziczone atrybuty i metody albo przez `super()`. ```python class Base: def greet(self) -> str: return "hello" class Child(Base): def greet(self) -> str: return super().greet() + " world" ``` **W skrócie:** - Odziedziczone składowe są dostępne w klasie pochodnej automatycznie. - `super()` poprawnie wywołuje logikę klasy bazowej. - To ważne przy rozszerzaniu, a nie duplikowaniu zachowania.
133. Do czego służy funkcja `super()` w dziedziczeniu w Pythonie i jak się jej używa? #### Python `super()` zwraca obiekt pośredniczący do następnej klasy zgodnie z MRO, aby wywołać jej metody. Typowo używa się jej w `__init__` oraz przy kooperatywnym wielokrotnym dziedziczeniu. ```python class Child(Base): def __init__(self, value: int) -> None: super().__init__() self.value = value ``` **W skrócie:** - `super()` wywołuje implementację klasy bazowej bez twardego wskazywania jej nazwy. - Pomaga zachować poprawność względem MRO. - To zalecany sposób pracy z dziedziczeniem.
134. Opisz funkcję `isinstance()` w Pythonie i podaj przykład jej użycia. #### Python `isinstance(obj, cls_or_tuple)` sprawdza, czy obiekt należy do danego typu albo jego podklasy. ```python isinstance(10, int) # True isinstance(True, int) # True isinstance("x", (str, bytes)) # True ``` **W skrócie:** - `isinstance` jest bezpieczniejsze niż `type(obj) is ...` w kodzie polimorficznym. - Uwzględnia hierarchię dziedziczenia. - Obsługuje krotkę typów.
135. Wyjaśnij funkcję `issubclass()` w Pythonie i podaj przykład jej zastosowania. #### Python `issubclass(Sub, Base)` sprawdza, czy klasa `Sub` jest podklasą `Base`. ```python class Animal: ... class Dog(Animal): ... issubclass(Dog, Animal) # True ``` **W skrócie:** - Działa na klasach, a nie na instancjach. - Jest wygodna do walidacji API na poziomie typów. - Uwzględnia dziedziczenie tranzytywne.
136. Czym jest wielokrotne dziedziczenie? #### Python Wielokrotne dziedziczenie oznacza dziedziczenie jednej klasy po kilku klasach bazowych. ```python class A: ... class B: ... class C(A, B): ... ``` Daje elastyczność, ale wymaga dyscypliny w projektowaniu metod i używaniu `super()`. **W skrócie:** - Jedna klasa może dziedziczyć zachowanie z kilku źródeł. - Jest przydatne w podejściu opartym na mixinach. - Może utrudniać zrozumienie MRO.
137. Jak działa MRO (Method Resolution Order) przy wielokrotnym dziedziczeniu? #### Python MRO określa kolejność wyszukiwania metod w hierarchii klas. W Pythonie używany jest algorytm linearyzacji C3. **Problem diamentu:** To klasyczny przypadek, gdy klasa `D` dziedziczy po `B` i `C`, a obie te klasy dziedziczą po `A`. MRO gwarantuje, że `A` zostanie rozpatrzona dopiero po wszystkich jej potomkach, czyli `B` i `C`. ```python class A: pass class B(A): pass class C(A): pass class D(B, C): pass print(D.mro()) # [D, B, C, A, object] ``` Kolejność można sprawdzić przez `ClassName.__mro__` albo `ClassName.mro()`. **W skrócie:** - MRO decyduje, z której klasy bazowej pobrać metodę. - Kolejność jest przewidywalna i formalnie określona przez C3. - Dzięki MRO Python poprawnie obsługuje problem diamentu. - Przy kooperatywnym dziedziczeniu wszystkie klasy powinny wywoływać `super()`.
138. Jakie są zalety i wady używania wielokrotnego dziedziczenia? #### Python Zalety: - ponowne użycie zachowania z kilku źródeł; - wygodne mixiny do "dodawania" możliwości. Wady: - bardziej złożone MRO; - ryzyko konfliktów nazw i zachowań; - trudniejsze debugowanie i wdrożenie w temat. **W skrócie:** - Wielokrotne dziedziczenie jest potężne, ale wymaga ścisłych zasad projektowych. - W większości przypadków kompozycja jest prostsza. - Używaj go głównie dla niewielkich mixinów.
139. Czym są mixiny? #### Python Mixin to niewielka klasa z wąskim dodatkowym zachowaniem, przeznaczona do łączenia przez dziedziczenie, a nie do samodzielnego użycia. Przykłady: `TimestampMixin`, `JsonSerializableMixin`. **W skrócie:** - Mixin dodaje jedną konkretną możliwość. - Zwykle nie ma własnego pełnego cyklu życia. - Dobrze łączy się z wielokrotnym dziedziczeniem.
140. Czym jest enkapsulacja w Pythonie? #### Python Enkapsulacja to ukrywanie wewnętrznej implementacji za stabilnym publicznym API. W Pythonie realizuje się to głównie przez konwencje i `property`, a nie przez sztywne modyfikatory dostępu. **W skrócie:** - Kod kliencki pracuje z interfejsem, a nie z detalami. - Enkapsulacja zmniejsza sprzężenie między komponentami. - Ułatwia zmianę wewnętrznej implementacji bez psucia API.
141. Jaka jest różnica między dostępem publicznym, prywatnym i chronionym? #### Python W Pythonie są to głównie konwencje nazewnicze: - `public`: `name` — dostępny wszędzie; - `protected`: `_name` — do użytku wewnętrznego zgodnie z konwencją; - `private`: `__name` — powoduje zmianę nazwy, czyli `_ClassName__name`, ale nie daje absolutnej ochrony. **W skrócie:** - Python nie ma ścisłych modyfikatorów dostępu jak Java czy C#. - `_name` i `__name` są sygnałami intencji dla programistów. - Realna kontrola dostępu wynika z projektu API.
142. Czym jest polimorfizm i jak jest realizowany w Pythonie? #### Python Polimorfizm to możliwość pracy z różnymi obiektami przez wspólny interfejs. W Pythonie często realizuje się go przez typowanie oparte na zachowaniu i protokoły. ```python def render(obj) -> str: return obj.to_text() ``` Każdy obiekt z metodą `to_text` będzie odpowiedni. **W skrócie:** - Jeden interfejs, wiele implementacji. - W Pythonie polimorfizm jest często "behawioralny", a nie hierarchiczny. - To upraszcza rozszerzanie systemu o nowe typy.
143. Czym jest abstrakcja w Pythonie? #### Python Abstrakcja to wyodrębnienie istotnego API i ukrycie zbędnych szczegółów implementacji. Klient pracuje z kontraktem, a nie z wewnętrznymi krokami. **W skrócie:** - Abstrakcja zmniejsza obciążenie poznawcze. - Ułatwia wymianę implementacji bez zmian w kodzie klienckim. - Jest realizowana przez interfejsy, ABC, protokoły i fasady.
144. Jak zaimplementować abstrakcję danych? #### Python Podejście: - ukryć bezpośredni dostęp do pól wewnętrznych, na przykład `_field`; - udostępnić kontrolowane API przez metody albo `@property`; - walidować inwarianty w logice settera. ```python class Temperature: def __init__(self, celsius: float) -> None: self.celsius = celsius @property def celsius(self) -> float: return self._celsius @celsius.setter def celsius(self, value: float) -> None: if value < -273.15: raise ValueError("invalid temperature") self._celsius = value ``` **W skrócie:** - Abstrakcja danych chroni inwarianty obiektu. - `property` daje kontrolowany dostęp do stanu. - Szczegóły wewnętrzne można zmieniać bez zmiany API.
145. Czym są ABC i `@abstractmethod`? #### Python ABC, czyli Abstract Base Class, to abstrakcyjna klasa bazowa z modułu `abc`. `@abstractmethod` oznacza metodę, którą podklasa musi obowiązkowo zaimplementować. ```python from abc import ABC, abstractmethod class Storage(ABC): @abstractmethod def save(self, data: bytes) -> None: ... ``` **W skrócie:** - ABC formalizuje kontrakt hierarchii. - `@abstractmethod` uniemożliwia utworzenie instancji niepełnej implementacji. - To przydatne w architekturach wtyczkowych i rozszerzalnych.
146. Czym jest property w Pythonie i jak się go używa? #### Python `property` zamienia metody dostępowe w API przypominające atrybut, z możliwością walidacji, obliczeń albo logiki leniwej. ```python class User: def __init__(self, name: str) -> None: self._name = name @property def name(self) -> str: return self._name ``` **W skrócie:** - `property` daje kontrolę dostępu bez zmiany zewnętrznej składni. - Nadaje się do walidacji i wartości pochodnych. - Pozwala rozwijać API bez psucia kodu klientów.
147. Czym jest `@property`? #### Python `@property` to dekorator dla metody getter. Razem z `@x.setter` i `@x.deleter` tworzy kontrolowany atrybut. **W skrócie:** - `@property` pozwala odczytywać metodę jak pole. - Pomaga enkapsulować wewnętrzną implementację. - Często jest używane dla API zachowującego kompatybilność wsteczną.
148. Czym jest deskryptor w Pythonie? #### Python Deskryptor to obiekt, który implementuje `__get__`, `__set__` albo `__delete__` i steruje dostępem do atrybutów innej klasy. Na deskryptorach opierają się `property`, `classmethod` i `staticmethod`. **W skrócie:** - Deskryptor to niskopoziomowy mechanizm dostępu do atrybutów. - Pozwala wielokrotnie używać logiki walidacji i pośredniczenia pól. - To podstawa wielu technik metaprogramistycznych w Pythonie.
149. Czym różnią się property i deskryptor? #### Python `property` to gotowy wysokopoziomowy deskryptor dla jednego atrybutu. Własny deskryptor to bardziej ogólny mechanizm, który można wielokrotnie wykorzystać w wielu polach i klasach. **W skrócie:** - `property` jest prostsze i lokalne. - Deskryptor jest bardziej elastyczny i skalowalny. - `property` jest faktycznie zbudowane na protokole deskryptora.
150. Kiedy lepiej używać property, a kiedy deskryptora? #### Python Używaj `property`, gdy logika dotyczy jednego lub dwóch pól konkretnej klasy. Używaj deskryptora, gdy tę samą logikę, na przykład walidację, rzutowanie czy leniwą inicjalizację, trzeba wielokrotnie zastosować w wielu klasach. **W skrócie:** - Lokalna logika pola oznacza `property`. - Wielokrotne użycie polityki dostępu oznacza deskryptor. - Deskryptor opłaca się w dużych modelach domenowych.
151. Do czego używa się `setattr()`, `getattr()` i `hasattr()`? Jaka jest między nimi różnica? #### Python To funkcje dynamicznego dostępu do atrybutów: - `getattr(obj, name[, default])` — odczytać atrybut; - `setattr(obj, name, value)` — ustawić atrybut; - `hasattr(obj, name)` — sprawdzić, czy istnieje. ```python value = getattr(user, "email", None) if not hasattr(user, "active"): setattr(user, "active", True) ``` **W skrócie:** - `getattr/setattr/hasattr` służą do dynamicznej pracy z obiektami. - Są przydatne w kodzie generycznym, serializacji i adapterach. - Nie warto ich nadużywać, żeby nie stracić czytelności.
152. Wyjaśnij znaczenie metody `__set_name__` w deskryptorach Pythona i podaj przykład jej zastosowania. #### Python `__set_name__(self, owner, name)` jest wywoływana podczas tworzenia klasy i przekazuje deskryptorowi nazwę atrybutu, do którego został przypisany. ```python class Field: def __set_name__(self, owner, name): self.name = name ``` **W skrócie:** - `__set_name__` inicjalizuje deskryptor kontekstem klasy. - Pozwala tworzyć wielokrotnie używalne walidatory pól. - Uruchamia się raz na etapie tworzenia klasy.
153. Czym jest `dataclass` i kiedy warto go używać? #### Python `@dataclass` automatycznie generuje powtarzalny kod, taki jak `__init__`, `__repr__`, `__eq__`. Nadaje się do modeli danych bez złożonego zachowania. ```python from dataclasses import dataclass @dataclass(slots=True) class User: name: str active: bool = True ``` **W skrócie:** - `dataclass` skraca kod dla modeli danych. - To dobry wybór dla DTO i konfiguracji. - Przy złożonej walidacji często potrzebne są inne narzędzia.
154. Jaka jest różnica między `dataclass` a Pydantic? #### Python `dataclass` koncentruje się na wygodnym opisie struktury. Pydantic dodaje walidację w czasie działania, parsowanie i serializację danych. **W skrócie:** - `dataclass` jest lżejszy i szybszy dla modeli wewnętrznych. - Pydantic lepiej nadaje się do danych wejściowych i API. - Wybór zależy od potrzeby walidacji podczas działania programu.
155. Czym są podpowiedzi typów i po co są potrzebne? #### Python Podpowiedzi typów to adnotacje typów w sygnaturach i zmiennych, które tworzą jawny kontrakt. Poprawiają podpowiedzi IDE i analizę statyczną. **W skrócie:** - Podpowiedzi typów zwiększają zrozumiałość API. - Pozwalają wcześniej wykrywać pewną klasę błędów. - Są przydatne nawet w języku dynamicznym.
156. Jak działa statyczne sprawdzanie typów w `mypy`? #### Python `mypy` odczytuje adnotacje typów i analizuje kod bez uruchamiania, sprawdzając zgodność typów. Dzięki temu wychwytuje błędy integracyjne przed wykonaniem programu. **W skrócie:** - `mypy` wykonuje sprawdzanie podobne do kompilacji dla Pythona. - Najlepiej sprawdza się w CI. - Tryby ścisłe zmniejszają liczbę błędów produkcyjnych.
157. Jak zapewnić bezpieczeństwo typów w projekcie Pythona? #### Python - konsekwentnie dodawać adnotacje typów do publicznego API; - włączyć `mypy` albo `pyright` w CI; - używać `TypedDict`, `Protocol` i generyków; - minimalizować `Any` i niejawne rzutowania. **W skrócie:** - Bezpieczeństwo typów to proces, a nie jednorazowe działanie. - Największy efekt daje bramka CI dla typów. - Stopniowe zwiększanie rygoru działa lepiej niż podejście "big bang".
158. Czym jest `TypedDict`? #### Python `TypedDict` opisuje typowaną formę słownika: jakie klucze są oczekiwane i jakich typów są ich wartości. ```python from typing import TypedDict class UserPayload(TypedDict): name: str; active: bool ``` **W skrócie:** - `TypedDict` typuje `dict` o stałych kluczach. - Jest wygodny dla struktur podobnych do JSON. - Jest sprawdzany przez analizator statyczny.
159. Czym jest `Protocol` w typowaniu? #### Python `Protocol` opisuje kontrakt behawioralny, czyli typowanie strukturalne: typ jest zgodny, jeśli ma wymagane metody i atrybuty, niezależnie od dziedziczenia. **W skrócie:** - `Protocol` realizuje typowanie oparte na zachowaniu w statycznym typowaniu. - Zmniejsza silne powiązanie z konkretnymi klasami. - Jest przydatny dla testowalnych i rozszerzalnych API.
160. Czym są generyki w Pythonie? #### Python Generyki pozwalają pisać typy i funkcje parametryzowane innymi typami. We współczesnej składni: `class Box[T]: ...`, `def first[T](...) -> T`. **W skrócie:** - Generyki sprawiają, że typy stają się wielokrotnego użytku. - Wzmacniają bezpieczeństwo typów kolekcji i kontenerów. - Zmniejszają duplikację typowanego kodu.
161. Czym jest Pydantic i do czego jest używany? #### Python Pydantic to biblioteka do opisywania schematów danych z walidacją w czasie działania, konwersją typów i wygodną serializacją. Typowe zastosowania to modele żądania i odpowiedzi w FastAPI oraz konfiguracja aplikacji. **W skrócie:** - Pydantic waliduje dane zewnętrzne podczas działania programu. - Jest wygodny dla API i integracji. - Daje czytelne błędy walidacji i schematy danych.
162. Czym są wyjątki w Pythonie? #### Python Wyjątek to obiekt sygnalizujący błędną albo wyjątkową sytuację podczas wykonywania kodu. **W skrócie:** - Wyjątki przerywają normalny przepływ wykonania. - Należy je obsługiwać tam, gdzie można podjąć decyzję. - Poprawny model błędów zwiększa niezawodność systemu.
163. Jakie są trzy typy błędów w Pythonie i czym się różnią? #### Python - błędy składniowe: pojawiają się przed uruchomieniem; - wyjątki czasu wykonania: pojawiają się w trakcie działania; - błędy logiczne: kod działa, ale zwraca niepoprawny wynik. **W skrócie:** - Błędy składniowe i część błędów wykonania wychwytuje interpreter. - Błędy logiczne wykrywa się testami i przeglądem kodu. - Każdy typ wymaga innego podejścia diagnostycznego.
164. Jak używać `try`, `except`, `else` i `finally`? #### Python `try` zawiera ryzykowną operację, `except` obsługuje błąd, `else` wykonuje się, gdy błędu nie było, a `finally` wykonuje się zawsze, zwykle przy czyszczeniu zasobów. ```python try: data = load() except FileNotFoundError: data = {} else: validate(data) finally: close_connections() ``` **W skrócie:** - `else` warto zostawić dla kodu "ścieżki sukcesu". - `finally` służy do zasobów i czyszczenia. - Łap konkretne wyjątki, a nie "wszystko po kolei".
165. Co oznacza kolejność bloków `except`? #### Python Bloki `except` są sprawdzane od góry do dołu, dlatego najpierw umieszcza się najbardziej konkretne wyjątki, a ogólne, takie jak `Exception`, na końcu. **W skrócie:** - Kolejność `except` wpływa na to, który obsługujący blok zostanie uruchomiony. - Szeroki `except` na górze "połyka" przypadki specyficzne. - To krytyczne dla poprawnego przepływu odzyskiwania po błędzie.
166. Jakie jest przeznaczenie słowa kluczowego `assert` w kodzie Pythona? #### Python `assert` sprawdza inwariant i zgłasza `AssertionError`, jeśli warunek jest fałszywy. Nadaje się do wewnętrznych kontroli deweloperskich, a nie do walidacji danych wejściowych użytkownika. **W skrócie:** - `assert` dokumentuje, że "to powinno być prawdziwe". - Nie zastępuje produkcyjnej obsługi błędów. - Używaj go do kontraktów w logice wewnętrznej.
167. Czym `raise` różni się od zwykłego wypisania komunikatu o błędzie w Pythonie? #### Python `raise` zmienia przepływ sterowania i sygnalizuje błąd kodowi wywołującemu. `print` tylko wypisuje tekst i nie zatrzymuje błędnego scenariusza. **W skrócie:** - `raise` jest mechanizmem obsługi błędów, a `print` nie. - Wyjątki można centralnie przechwytywać i logować. - `print` służy do diagnostyki, a nie do kontraktu błędów.
168. Jak utworzyć własny wyjątek? #### Python Utwórz klasę dziedziczącą po `Exception` albo po bardziej konkretnym wyjątku bazowym. ```python class InvalidOrderError(Exception): pass ``` **W skrócie:** - Własny wyjątek czyni błędy bardziej wyrazistymi domenowo. - Pozwala precyzyjnie przechwytywać potrzebne przypadki. - Często jest lepszy niż używanie wszędzie ogólnego `ValueError`.
169. Jakie znaczenie ma tworzenie własnych wyjątków w Pythonie i jak poprawiają one obsługę błędów? #### Python Własne wyjątki budują jawny model błędów domeny i oddzielają problemy techniczne od reguł biznesowych. **W skrócie:** - Poprawiają czytelność i utrzymanie obsługi błędów. - Dają precyzyjniejszą semantykę w logach i API. - Ułatwiają testowanie scenariuszy negatywnych.
170. Jak są zorganizowane wyjątki w Pythonie i jaka jest hierarchia klas wyjątków? #### Python Hierarchia jest zbudowana od `BaseException`. W kodzie aplikacyjnym prawie zawsze pracuje się z potomkami `Exception`. Kluczowe gałęzie to `ValueError`, `TypeError`, `KeyError`, `OSError`, `RuntimeError`. **W skrócie:** - Wyjątki tworzą drzewo klas. - Lepiej przechwytywać konkretne podklasy. - `BaseException` zwykle nie jest przechwytywany w logice biznesowej.
171. Jakie są podejścia do obsługi kilku różnych wyjątków w Pythonie i dlaczego warto obsługiwać je osobno? #### Python Podejścia: - osobne `except` dla każdego typu; - grupowanie logicznie podobnych przypadków: `except (A, B):`; - osobne strategie odzyskiwania dla każdej kategorii. **W skrócie:** - Różne wyjątki często wymagają różnych działań. - Osobna obsługa zmniejsza ryzyko ukrytych defektów. - Logi stają się dokładniejsze i bardziej użyteczne.
172. Po co ponownie zgłaszać wyjątek w Pythonie i kiedy jest to przydatne? #### Python Ponowne zgłoszenie wyjątku, czyli `raise` bez argumentów w `except`, pozwala dodać kontekst, na przykład logi, metryki albo czyszczenie, i przekazać ten sam błąd wyżej. **W skrócie:** - Ponowne zgłoszenie zachowuje pierwotny ślad stosu. - Jest przydatne przy scentralizowanej obsłudze na wyższym poziomie. - Nie "połykaj" krytycznych błędów bez potrzeby.
173. Dlaczego użycie bloku try-except warto ograniczać w programach Pythona i jak wpływa to na wydajność? #### Python `try/except` jest potrzebne, ale nie powinno obejmować dużych bloków "na wszelki wypadek". Jest to szczególnie kosztowne, gdy wyjątki pojawiają się często i sterują przepływem programu. **W skrócie:** - Przechwytuj tylko oczekiwane błędy w możliwie wąskim miejscu. - Częste wyjątki pogarszają wydajność i czytelność. - Tam, gdzie to ma sens, lepsze są jawne sprawdzenia.
174. Jak obsługiwać błędy podczas pracy z plikami? #### Python Używaj `with` i przechwytuj konkretne wyjątki, takie jak `FileNotFoundError`, `PermissionError`, `UnicodeDecodeError` i `OSError`. ```python try: with open(path, "r", encoding="utf-8") as f: content = f.read() except FileNotFoundError: ... ``` **W skrócie:** - `with` gwarantuje zamknięcie pliku. - Obsługuj konkretne błędy wejścia i wyjścia. - Loguj kontekst, taki jak ścieżka, tryb i kodowanie.
175. Jakie są tryby pracy z plikami w Pythonie? #### Python Podstawowe tryby: - `r` odczyt; - `w` nadpisanie; - `a` dopisywanie na końcu; - `x` utworzenie nowego pliku; - `b` tryb binarny; - `t` tryb tekstowy, domyślny; - `+` odczyt i zapis. **W skrócie:** - Tryb określa semantykę bezpieczeństwa i zmian w pliku. - `w` usuwa poprzednią zawartość, a `a` ją zachowuje. - Dla danych bajtowych używaj `b`.
176. Dlaczego ważne jest zamykanie plików po operacjach i co może się stać, jeśli plik pozostanie otwarty? #### Python Otwarty plik utrzymuje deskryptor systemu operacyjnego. Jeśli go nie zamknąć, mogą wystąpić: - wyciek deskryptorów plików; - blokady plików lub niepełne opróżnienie bufora; - niestabilność w długotrwałych procesach. **W skrócie:** - Zamknięcie pliku zwalnia zasoby systemu operacyjnego. - `with` automatyzuje bezpieczne zamykanie. - To krytyczne dla usług i skryptów wsadowych.
177. Jaka jest różnica między metodami `read()`, `readline()` i `readlines()` przy odczycie plików? #### Python - `read()` czyta cały plik albo `n` bajtów lub znaków; - `readline()` czyta jeden wiersz; - `readlines()` czyta wszystkie wiersze do listy. **W skrócie:** - `read()` i `readlines()` mogą być kosztowne pamięciowo. - Dla dużych plików lepsza jest iteracja `for line in file`. - Wybór zależy od rozmiaru i scenariusza przetwarzania.
178. Jak zapisać dane do pliku w Pythonie i jaka jest różnica między trybem `w` a `a`? #### Python Zapis: ```python with open("out.txt", "w", encoding="utf-8") as f: f.write("hello\n") ``` `w` nadpisuje plik od początku, a `a` dopisuje nową treść na końcu. **W skrócie:** - `w` usuwa stare dane. - `a` zachowuje istniejącą zawartość. - Do logów zwykle używa się `a`.
179. Jak efektywnie pracować z dużymi plikami? #### Python - czytać strumieniowo, po wierszach albo blokach; - unikać ładowania całego pliku do pamięci; - używać buforowania i generatorów; - dla danych kolumnowych i tabelarycznych dobierać odpowiednie formaty i parsery. **W skrócie:** - Klucz to przetwarzanie strumieniowe zamiast pełnego odczytu. - Generatory zmniejszają zużycie pamięci. - Algorytm przetwarzania jest ważniejszy niż mikrooptymalizacje.
180. Czym są menedżery kontekstu? #### Python Menedżer kontekstu zarządza zasobem przez protokół `__enter__/__exit__`: otwarcie lub inicjalizację oraz gwarantowane zakończenie i czyszczenie. **W skrócie:** - Zapewnia bezpieczny cykl życia zasobu. - Działa przez `with`. - Zmniejsza liczbę wycieków zasobów.
181. Jak działa konstrukcja `with`? #### Python `with` wywołuje `__enter__` przy wejściu do bloku i `__exit__` przy wyjściu, nawet jeśli wystąpił błąd. ```python with open("data.txt", "r", encoding="utf-8") as f: data = f.read() ``` **W skrócie:** - `with` gwarantuje czyszczenie zasobów. - Sprawia, że praca z zasobami jest deklaratywna. - Jest zalecany dla plików, blokad, transakcji i sesji.
182. Jak utworzyć własny menedżer kontekstu? #### Python Dwa podejścia: - klasa z `__enter__` i `__exit__`; - funkcja z dekoratorem `contextlib.contextmanager`. ```python from contextlib import contextmanager @contextmanager def temp_flag(): yield ``` **W skrócie:** - Klasa nadaje się do złożonego stanu. - `contextmanager` jest wygodny dla krótkich scenariuszy. - Oba podejścia dają gwarantowane czyszczenie.
183. Jak Python zarządza pamięcią? #### Python CPython używa zliczania referencji i cyklicznego mechanizmu odśmiecania pamięci. Dodatkowo ma wewnętrzny alokator `pymalloc` dla małych obiektów. **W skrócie:** - Podstawowy mechanizm to licznik referencji. - GC usuwa cykliczne referencje. - Pamięć nie zawsze jest zwalniana natychmiast na poziomie systemu operacyjnego.
184. Czym jest zliczanie referencji w Pythonie i dlaczego jest ważne dla zarządzania pamięcią? #### Python Każdy obiekt ma licznik referencji. Gdy spada on do zera, obiekt można zwolnić. Zapewnia to szybkie usuwanie większości krótkotrwałych obiektów. **W skrócie:** - Zliczanie referencji daje przewidywalny cykl życia obiektów. - Samodzielnie nie rozwiązuje problemu cyklicznych referencji. - Razem z GC tworzy pełny model zarządzania pamięcią.
185. Czym jest odśmiecanie pamięci w Pythonie? #### Python Odśmiecanie pamięci w CPython znajduje i usuwa nieosiągalne cykle obiektów, których nie da się wyczyścić wyłącznie przez zliczanie referencji. **W skrócie:** - GC uzupełnia zliczanie referencji. - Jest szczególnie ważny dla cyklicznych grafów referencji. - Można nim sterować przez moduł `gc`.
186. Jak uzyskać adres pamięci obiektu w Pythonie? #### Python W CPython `id(obj)` często odpowiada adresowi obiektu w pamięci jako liczba całkowita. To narzędzie diagnostyczne, a nie stabilny identyfikator zewnętrzny. **W skrócie:** - `id()` daje tożsamość obiektu. - W CPython zwykle jest to adres pamięci. - Nie używaj tego w logice biznesowej.
187. Do czego służy funkcja `getrefcount()` z modułu `sys` i jak działa w Pythonie? #### Python `sys.getrefcount(obj)` zwraca bieżący licznik referencji do obiektu w CPython. Wartość jest zwykle o 1 większa przez tymczasową referencję argumentu. **W skrócie:** - To narzędzie diagnostyki zachowania pamięci. - Jest przydatne do analizy wycieków referencji. - Nie należy na nim polegać w logice aplikacyjnej.
188. Wyjaśnij na przykładach różnicę między obiektami mutable i immutable w kontekście zliczania referencji i zarządzania pamięcią. #### Python Obiekty immutable się nie zmieniają, więc ich "zmiana" tworzy nowy obiekt. Obiekty mutable zmieniają się in-place i wszystkie referencje widzą tę zmianę. ```python a = "x"; b = a; a += "y" # nowy obiekt x = [1]; y = x; y.append(2) # zmiana tego samego obiektu ``` **W skrócie:** - Obiekty immutable zmniejszają liczbę efektów ubocznych. - Obiekty mutable są bardziej efektywne przy modyfikacjach in-place. - Ta różnica jest krytyczna przy kopiowaniu i współdzielonych referencjach.
189. Jaka jest różnica między kopią płytką a kopią głęboką w Pythonie i kiedy używać każdego z tych podejść? #### Python Kopia płytka kopiuje tylko zewnętrzny kontener, a zagnieżdżone obiekty pozostają współdzielone. Kopia głęboka rekurencyjnie kopiuje całą strukturę. ```python import copy copy.copy(obj) copy.deepcopy(obj) ``` **W skrócie:** - Kopia płytka wystarcza dla "płaskich" struktur. - Kopia głęboka jest potrzebna do izolowanej pracy z zagnieżdżonymi danymi mutable. - Kopia głęboka jest droższa czasowo i pamięciowo.
190. Czym są moduły i pakiety w Pythonie? #### Python Moduł to osobny plik `.py` z kodem. Pakiet to katalog modułów, czyli przestrzeń nazw, która organizuje kod w większe bloki. **W skrócie:** - Moduł to jednostka kodu. - Pakiet to struktura do skalowania modułów. - Podział na moduły i pakiety poprawia utrzymywalność.
191. Jak importować moduł w Pythonie? #### Python Podstawowe formy: - `import module`; - `import module as m`; - `from module import name`; - `from package import submodule`. **W skrócie:** - Import ładuje moduł i udostępnia go w przestrzeni nazw. - Alias `as` poprawia czytelność i pomaga unikać konfliktów. - Warto preferować jawne importy.
192. Jakie są typy importów? #### Python Popularne typy: - bezwzględne; - względne; - wybiórcze, jak `from x import y`; - importy z aliasem przez `as`; - dynamiczne, z użyciem `importlib`. **W skrócie:** - Typ importu wpływa na czytelność i utrzymanie. - W kodzie produkcyjnym najczęściej używa się importów bezwzględnych. - Importy dynamiczne stosuje się punktowo.
193. Jak działa system importów? #### Python Interpreter szuka modułu według `sys.path`, ładuje go tylko raz i zapisuje w `sys.modules`. Ponowny import korzysta z pamięci podręcznej. **W skrócie:** - Import to wyszukiwanie, wykonanie modułu i zapisanie go w pamięci podręcznej. - To wyjaśnia, dlaczego kod modułu uruchamia się przy pierwszym imporcie. - Cykliczne importy wynikają z kolejności inicjalizacji modułów.
194. Jaka jest różnica między importem bezwzględnym a względnym? #### Python Import bezwzględny zaczyna się od korzenia pakietu, na przykład `from app.utils import x`. Import względny używa kropek, na przykład `from .utils import x`. **W skrócie:** - Importy bezwzględne są czytelniejsze i stabilniejsze. - Względne bywają wygodne wewnątrz pakietu, ale gorzej znoszą refaktoryzację. - W dużych projektach lepiej standardowo trzymać się importów bezwzględnych.
195. Co robi funkcja `dir()` i jak można jej używać względem modułów? #### Python `dir(obj)` zwraca listę dostępnych atrybutów i nazw obiektu. W przypadku modułów to szybki sposób na podejrzenie API. ```python import math dir(math) ``` **W skrócie:** - `dir()` pomaga w interaktywnym poznawaniu modułów. - Jest przydatne w REPL i podczas debugowania. - Nie zastępuje oficjalnej dokumentacji.
196. Wyjaśnij rolę konstrukcji `if __name__ == "__main__":` w skryptach Pythona. #### Python Ten blok wykonuje się tylko wtedy, gdy plik jest uruchamiany jako skrypt, a nie importowany jako moduł. Rozdziela to kod wielokrotnego użytku od punktu wejścia CLI. **W skrócie:** - Pozwala moduł zarówno uruchamiać, jak i importować. - Zapobiega niechcianemu wykonaniu podczas importu. - To standardowy wzorzec dla skryptów.
197. Co oznacza plik `__init__.py` w pakiecie Pythona? #### Python `__init__.py` oznacza katalog jako pakiet i może inicjalizować API na poziomie pakietu, na przykład przez ponowny eksport klas i funkcji. **W skrócie:** - Tworzy publiczny interfejs pakietu. - Może zawierać minimalną inicjalizację. - Nie warto przeciążać go ciężką logiką.
198. Jakie są najlepsze praktyki dotyczące stylu importów w kodzie Pythona? #### Python - grupować importy: biblioteka standardowa, zewnętrzne i lokalne; - unikać `from x import *`; - trzymać importy na początku pliku, poza uzasadnionymi przypadkami leniwego importu; - używać sortowania i formatowania, na przykład `ruff` oraz `isort`. **W skrócie:** - Spójne importy poprawiają czytelność. - Jawne importy zmniejszają konflikty nazw. - Automatyzacja narzędziami eliminuje ręczne błędy.
199. Jakie popularne moduły wbudowane istnieją w Pythonie? #### Python Przykłady popularnych modułów biblioteki standardowej: - `os`, `sys`, `pathlib`, `json`, `datetime`, `re`, - `collections`, `itertools`, `functools`, `typing`, - `asyncio`, `subprocess`, `logging`, `argparse`. **W skrócie:** - Biblioteka standardowa pokrywa większość podstawowych zadań. - To zmniejsza liczbę zależności zewnętrznych. - Warto dobrze znać bibliotekę standardową przed dodawaniem pakietów zewnętrznych.
200. Co wiesz o pakiecie `collections` i jakie inne moduły wbudowane były używane? #### Python `collections` udostępnia wysokopoziomowe struktury: - `Counter`, `defaultdict`, `deque`, `namedtuple`, `ChainMap`. Typowo łączy się go z: - `itertools` do potoków iteracyjnych; - `functools` do buforowania wyników i narzędzi funkcyjnych; - `pathlib`, `json`, `datetime` w zadaniach praktycznych. **W skrócie:** - `collections` rozszerza podstawowe kontenery o praktyczne struktury. - Często zwiększa prostotę i wydajność kodu. - Dobrze współpracuje z `itertools` i `functools`.
201. Co zwraca `sys.argv`? #### Python `sys.argv` zwraca listę argumentów wiersza poleceń: - `sys.argv[0]` to nazwa skryptu; - pozostałe elementy to przekazane argumenty. **W skrócie:** - `sys.argv` to podstawowy interfejs argumentów CLI. - Wartości przychodzą jako napisy. - Dla bardziej złożonych CLI lepsze jest `argparse`.
202. Jaki jest główny moduł do pracy z systemem operacyjnym w Pythonie? #### Python Podstawowym modułem jest `os`, razem z `os.path`, a dla nowoczesnego API ścieżek zalecany jest `pathlib`. **W skrócie:** - `os` daje dostęp do API procesów, środowiska i systemu plików. - `pathlib` jest wygodniejszy do pracy ze ścieżkami. - W realnych projektach często używa się obu.
203. Jak przetasować elementy listy za pomocą modułu `random`? #### Python Użyj `random.shuffle(list_)` do tasowania in-place. ```python import random items = [1, 2, 3, 4] random.shuffle(items) ``` **W skrócie:** - `shuffle` zmienia oryginalną listę. - Działa tylko z mutowalnymi sekwencjami, na przykład listami. - Aby otrzymać nową kopię, użyj `random.sample(items, k=len(items))`.
204. Czym jest środowisko wirtualne? #### Python Środowisko wirtualne to izolowane środowisko Pythona z własnymi pakietami i wersjami zależności dla konkretnego projektu. **W skrócie:** - Izolacja usuwa konflikty zależności między projektami. - Standardowym narzędziem jest `venv`. - To podstawowa praktyka dla odtwarzalnego rozwoju projektu.
205. Jak działa `pip`? #### Python `pip` instaluje, aktualizuje i usuwa pakiety z indeksów, najczęściej z PyPI, rozwiązuje zależności i instaluje je w bieżącym środowisku. **W skrócie:** - `pip` to standardowy menedżer pakietów Pythona. - Działa w obrębie aktywnego venv i interpretera. - Dla stabilności ważne są przypięte wersje.
206. Czym jest `requirements.txt`? #### Python `requirements.txt` to plik z listą zależności, często z dokładnymi wersjami, używany do odtwarzalnej instalacji. **W skrócie:** - Format jest prosty i zgodny z `pip install -r`. - W środowisku produkcyjnym najlepiej przypinać dokładne wersje. - Często jest generowany narzędziami, na przykład `pip-tools` albo `poetry export`, na podstawie deklaratywnej listy zależności lub plików lock.
207. Czym jest `pyproject.toml` i dlaczego stał się standardem? #### Python `pyproject.toml` to ustandaryzowany plik konfiguracji projektu: metadane pakietu, system budowania i ustawienia narzędzi, takich jak `ruff`, `pytest`, `mypy`. **W skrócie:** - Centralizuje konfigurację projektu Python. - Jest wspierany przez nowoczesne narzędzia pakowania. - Zmniejsza liczbę rozproszonych plików konfiguracyjnych.
208. Jak zarządzać zależnościami w nowoczesnym projekcie Pythona? #### Python - izolować środowisko przez `venv`; - definiować zależności w `pyproject.toml`; - przypinać pliki lock albo constraints dla odtwarzalności; - regularnie aktualizować z kontrolą przez CI. **W skrócie:** - Zarządzanie zależnościami powinno być odtwarzalne. - Nie mieszaj pakietów globalnych i projektowych. - Aktualizacje wykonuj w kontrolowany sposób, przez testy.
209. Jak poprawnie zorganizować strukturę dużego projektu Pythona? #### Python - podzielić kod na pakiety domenowe; - mieć osobne warstwy, takie jak `api`, `services`, `domain`, `infrastructure`; - wydzielić `tests/`, `scripts/`, `configs/`; - utrzymywać jawne granice modułów i publiczne API. **W skrócie:** - Struktura powinna odzwierciedlać domenę, a nie przypadkowe szczegóły techniczne. - Wyraźne granice zmniejszają liczbę cyklicznych zależności. - Testy i narzędzia powinny być pełnoprawną częścią drzewa projektu.
210. Jaka jest różnica między testowaniem automatycznym a ręcznym i jakie są zalety testowania automatycznego? #### Python Testowanie ręczne wykonuje człowiek krok po kroku. Testowanie automatyczne jest wykonywane przez skrypty albo struktury testowe. **W skrócie:** - Testy automatyczne są szybkie, powtarzalne i nadają się do CI. - Testowanie ręczne jest przydatne dla eksploracyjnych scenariuszy UX. - W praktyce produkcyjnej potrzebne jest połączenie obu podejść.
211. Czym jest TDD (Test-Driven Development)? #### Python TDD to cykl: napisać nieprzechodzący test -> minimalna implementacja -> refaktoryzacja. **W skrócie:** - TDD kształtuje API przez testy. - Daje szybki sygnał zwrotny o regresjach. - Najlepiej sprawdza się w modułowej logice biznesowej.
212. Jakie są popularne narzędzia testowe w Pythonie? #### Python Najpopularniejsze to `pytest`, `unittest` z biblioteki standardowej oraz `hypothesis` do testów opartych na właściwościach. **W skrócie:** - `pytest` jest najczęściej wybierany do nowych projektów. - `unittest` jest przydatny jako standardowe podstawowe narzędzie. - `hypothesis` wzmacnia pokrycie przypadków brzegowych.
213. Czym jest `unittest` w Pythonie? #### Python `unittest` to wbudowane narzędzie w stylu xUnit do testów: klasy przypadków testowych, metody asercji, przygotowanie i sprzątanie oraz uruchamianie testów. **W skrócie:** - Jest częścią biblioteki standardowej. - Nadaje się do konserwatywnych środowisk bez zależności zewnętrznych. - Ma bardziej rozbudowaną składnię niż `pytest`.
214. Czym jest `pytest` i czym różni się od `unittest` pod względem składni i funkcjonalności? #### Python `pytest` to narzędzie z prostą składnią testów funkcyjnych, rozbudowanymi fixture'ami, parametryzacją i ekosystemem wtyczek. **W skrócie:** - `pytest` ma mniej szablonowy styl i jest wygodniejszy dla dużych zestawów testów. - `unittest` jest oparty na klasach i standardowy w bibliotece standardowej. - W nowoczesnych projektach dominuje `pytest`.
215. Opisz, jak metoda `pytest.raises` jest używana do testowania wystąpienia konkretnych wyjątków w kodzie Pythona. #### Python `pytest.raises(ExpectedError)` sprawdza, czy blok kodu zgłasza dokładnie oczekiwany wyjątek. ```python import pytest with pytest.raises(ValueError): int("abc") ``` **W skrócie:** - Jawnie testuje scenariusze negatywne. - Chroni przed "cichym" przechodzeniem błędów. - Może też sprawdzać komunikat lub atrybuty wyjątku.
216. Czym jest parametryzacja w testach i jak pytest wspiera ją przez `@pytest.mark.parametrize`? #### Python Parametryzacja uruchamia jeden test dla kilku zestawów danych wejściowych. W pytest robi się to dekoratorem `@pytest.mark.parametrize`. **W skrócie:** - Daje mniej duplikacji kodu testowego. - Łatwo skalować przypadki. - Zwiększa przejrzystość pokrycia scenariuszy wejściowych.
217. Jak w pytest nadać własne nazwy testom w parametryzacji dla lepszej czytelności? #### Python Użyj parametru `ids` w `parametrize`. ```python @pytest.mark.parametrize("value,expected", [(2, True), (3, False)], ids=["even", "odd"]) ``` **W skrócie:** - `ids` czyni wynik uruchomienia testów bardziej zrozumiałym. - Ułatwia diagnozowanie niepowodzeń. - Jest szczególnie przydatny przy dużej liczbie przypadków.
218. Czym jest etap przygotowania testu i dlaczego to ważne? #### Python Etap przygotowania testu to ustawienie stanu testowego: danych, obiektów, mocków i środowiska. Dobrze przygotowane środowisko sprawia, że test jest deterministyczny. **W skrócie:** - Niestabilne przygotowanie oznacza niestabilne testy. - Dobre przygotowanie izoluje test od efektów zewnętrznych. - Jasny etap przygotowania poprawia czytelność scenariusza.
219. Jakie etapy obejmuje sprzątanie po teście i dlaczego to ważne? #### Python Sprzątanie po teście usuwa wszystko, co utworzył test: pliki tymczasowe, połączenia, mocki i testowe rekordy w bazie danych. **W skrócie:** - Sprzątanie zapewnia izolację między testami. - Zmniejsza efekty uboczne i niestabilność testów. - W pytest wygodnie robi się to przez finalizery fixture i fixture oparte na `yield`.
220. Jaka jest różnica między metodami `setUp()` i `setUpClass()` w unittest? #### Python `setUp()` wykonuje się przed **każdą** metodą testową. `setUpClass()` jako metoda klasowa wykonuje się **jeden raz** przed wszystkimi testami klasy. **W skrócie:** - `setUp` służy do izolacji na poziomie pojedynczego testu. - `setUpClass` służy do kosztownych współdzielonych zasobów. - Nadmierny współdzielony stan przez `setUpClass` może komplikować testy.
221. Czym jest obiekt pozorowany i jak pomaga podnieść jakość testów? #### Python Obiekt pozorowany to obiekt zastępczy, który imituje zależność i pozwala kontrolować zachowanie oraz sprawdzać wywołania. **W skrócie:** - Mocki izolują testowaną jednostkę od usług zewnętrznych. - Sprawiają, że testy są szybsze i stabilniejsze. - Pozwalają sprawdzać interakcje, a nie tylko wynik.
222. Jaka jest różnica między użyciem `mock.patch` w unittest a `monkeypatch` w pytest do mockowania obiektów? #### Python `mock.patch` z `unittest.mock` podmienia obiekty według ścieżki importu i ma rozbudowane API do sprawdzania wywołań. `monkeypatch` w pytest w prostszy sposób zmienia atrybuty, zmienne środowiskowe i słowniki na czas testu. **W skrócie:** - `patch` jest potężniejszy w scenariuszach z asercjami na mockach. - `monkeypatch` jest wygodny do szybkich testowych podmian. - Często używa się ich łącznie, zależnie od przypadku.
223. Jakie jest przeznaczenie parametru `scope` w fixture'ach pytest? #### Python `scope` określa cykl życia fixture'a: `function`, `class`, `module`, `package`, `session`. **W skrócie:** - Mniejszy scope oznacza lepszą izolację. - Większy scope oznacza szybsze uruchamianie dużych zestawów testów. - Wybór zasięgu to balans między szybkością a niezależnością.
224. Czym jest złożoność algorytmu i jak się ją określa? #### Python Złożoność algorytmu ocenia, jak rosną koszty czasu i pamięci wraz ze wzrostem rozmiaru danych wejściowych `n`. **W skrócie:** - Mierzy się złożoność czasową i pamięciową. - Ocena jest zwykle asymptotyczna. - Pomaga wybierać algorytm i struktury danych.
225. Wyjaśnij pojęcie notacji Big O i jej znaczenie w ocenie złożoności algorytmów. #### Python Big O opisuje górną granicę wzrostu kosztu algorytmu przy dużym `n`, pomijając stałe i składniki niższego rzędu. **W skrócie:** - Big O pokazuje skalowalność, a nie dokładny czas. - Daje wspólny język do porównywania algorytmów. - Jest krytycznie ważna dla wydajności przy dużych wolumenach danych.
226. Jakie rodzaje złożoności algorytmicznej występują najczęściej? #### Python Najczęstsze to `O(1)`, `O(log n)`, `O(n)`, `O(n log n)`, `O(n^2)`. **W skrócie:** - `O(n)` i `O(n log n)` są najtypowsze w zadaniach praktycznych. - `O(n^2)` i więcej często staje się wąskim gardłem. - Trzeba brać pod uwagę także pamięć, a nie tylko czas.
227. Podaj przykłady zadań, które są efektywnie rozwiązywane przez algorytmy liniowe `O(n)`. #### Python Przykłady: - szukanie maksimum i minimum; - filtrowanie elementów; - zliczanie częstotliwości przez `Counter`; - sprawdzanie warunków dla każdego elementu. **W skrócie:** - `O(n)` oznacza jedno przejście po danych. - To rozwiązanie optymalne dla wielu agregacji. - Algorytmy liniowe dobrze się skalują.
228. Jak działa `lru_cache` i kiedy go używać? #### Python `functools.lru_cache` buforuje wyniki funkcji według argumentów i zwraca gotową wartość przy kolejnych wywołaniach. **W skrócie:** - Jest skuteczny dla funkcji czystych z powtarzającymi się danymi wejściowymi. - Nie nadaje się do funkcji z efektami ubocznymi. - `maxsize` kontroluje rozmiar bufora w pamięci.
229. Jak profilować wydajność kodu Pythona? #### Python Podstawowe narzędzia: - `timeit` do mikrobenchmarków; - `cProfile` i `pstats` do profilowania na poziomie wywołań; - `py-spy` i `scalene` do analizy zbliżonej do warunków produkcyjnych. **W skrócie:** - Optymalizuj dopiero po pomiarach. - Profiluj realistyczne scenariusze obciążenia. - Ustalaj punkt odniesienia przed i po zmianach.
230. Jakie są podstawowe sposoby optymalizacji kodu Pythona? #### Python - dobrać właściwe struktury danych; - zmniejszyć złożoność asymptotyczną; - unikać zbędnych kopii; - używać generatorów i leniwych potoków; - buforować kosztowne obliczenia; - przenosić najbardziej gorące ścieżki do C, Rust lub NumPy, jeśli to potrzebne. **W skrócie:** - Największy zysk daje algorytm, a nie składniowa sztuczka. - Optymalizacja musi opierać się na profilowaniu. - Nie warto poświęcać czytelności bez zmierzonej korzyści.
231. Kiedy warto używać rozszerzeń C albo PyPy? #### Python Rozszerzenia C są zasadne dla wąskich gardeł CPU i integracji z bibliotekami natywnymi. PyPy jest zasadne wtedy, gdy długowieczny czysty kod Pythona korzysta z kompilacji JIT. **W skrócie:** - Rozszerzenie C daje maksymalną wydajność kosztem złożoności budowania. - PyPy daje potencjalny wzrost wydajności bez przepisywania kodu na C. - Wybór powinien wynikać z pomiarów wydajności dla rzeczywistego obciążenia.
232. Czym jest profilowanie pamięci? #### Python Profilowanie pamięci to mierzenie, gdzie i ile pamięci zużywa kod w czasie, aby znaleźć wycieki i kosztowne miejsca. **W skrócie:** - Pokazuje gorące miejsca pamięci i piki zużycia. - Jest przydatne dla obciążeń wsadowych i przetwarzania danych. - Narzędzia: `tracemalloc`, `memory_profiler`, `scalene`.
233. Czym jest GIL (globalna blokada interpretera)? #### Python GIL to mechanizm w CPython, który pozwala tylko jednemu wątkowi jednocześnie wykonywać kod bajtowy Pythona w obrębie procesu. **W skrócie:** - GIL wpływa na wielowątkowość w zadaniach CPU-bound. - W zadaniach I/O-bound wątki nadal są użyteczne. - Do równoległości CPU częściej używa się multiprocessing.
234. Jak globalna blokada interpretera Pythona wpływa na współbieżność w CPython i jakie ma to konsekwencje dla wielowątkowości? #### Python Przez GIL wątki w CPython nie wykonują kodu bajtowego Pythona naprawdę równolegle dla kodu CPU-bound. Przełączają się współbieżnie. Konsekwencje: - dla wątków I/O-bound efekt jest dobry, bo oczekiwanie na I/O może się nakładać; - dla zadań CPU-bound zysk z wątków jest zwykle ograniczony. **W skrócie:** - GIL ogranicza równoległość wątków w scenariuszach CPU-bound. - Wątki pozostają użyteczne dla sieci i dysku. - Dla CPU lepiej używać procesów albo obliczeń natywnych.
235. Jak GIL wpływa na wydajność? #### Python GIL prawie nie przeszkadza w zadaniach I/O-bound, ale ogranicza przepustowość wielowątkowego kodu Pythona CPU-bound w jednym procesie. **W skrócie:** - Wpływ GIL zależy od rodzaju obciążenia. - CPU-bound plus wątki w CPython często się nie skaluje. - Architekturę należy dobierać do profilu zadań.
236. Wyjaśnij koncepcję wielowątkowości w Pythonie i czym różni się od multiprocessing. #### Python `threading` uruchamia kilka wątków w jednym procesie ze współdzieloną pamięcią. `multiprocessing` uruchamia osobne procesy z odrębną pamięcią. **W skrócie:** - Wątki są lżejsze i wygodne dla zadań I/O-bound. - Procesy dają rzeczywistą równoległość CPU. - Procesy mają większy narzut IPC i uruchamiania.
237. Kiedy używać multiprocessing zamiast threading? #### Python Gdy zadanie jest CPU-bound i wymaga użycia wielu rdzeni w CPython. Przykłady: ciężkie parsowanie, przetwarzanie obrazu i wideo, obliczenia numeryczne. **W skrócie:** - CPU-bound zwykle oznacza `multiprocessing`. - I/O-bound zwykle oznacza `threading` albo `asyncio`. - Trzeba uwzględniać koszt serializacji między procesami.
238. Jaka jest różnica między współbieżnością a równoległością w programowaniu i kiedy której z nich używać? #### Python Współbieżność oznacza nakładanie się zadań w czasie. Równoległość oznacza fizyczne wykonywanie zadań jednocześnie na kilku rdzeniach. **W skrócie:** - Współbieżność jest przydatna przy opóźnieniach I/O. - Równoległość jest potrzebna dla obliczeń intensywnie obciążających CPU. - W Pythonie wybór narzędzia zależy od rodzaju wąskiego gardła.
239. Czym jest współbieżność w Pythonie? #### Python Współbieżność w Pythonie to organizacja wykonywania wielu zadań tak, aby postępowały współbieżnie: przez wątki, `asyncio` albo procesy. **W skrócie:** - Chodzi o zarządzanie wieloma zadaniami, niekoniecznie równolegle. - Pozwala zwiększyć przepustowość scenariuszy I/O. - Wymaga starannego projektowania synchronizacji i anulowania.
240. Jaka jest różnica między zadaniami I/O-bound a CPU-bound? #### Python Zadania I/O-bound głównie czekają na sieć, dysk albo bazę danych. Zadania CPU-bound spędzają większość czasu na obliczeniach procesora. **W skrócie:** - I/O-bound dobrze skaluje się przez `asyncio` i wątki. - CPU-bound lepiej skaluje się przez `multiprocessing` i kod natywny. - Najpierw określ wąskie gardło przez profilowanie.
241. Do czego służy moduł `asyncio` w Pythonie i jak pozwala realizować programowanie asynchroniczne? #### Python `asyncio` udostępnia pętlę zdarzeń, planowanie zadań i asynchroniczne prymitywy do współbieżności kooperatywnej w zadaniach I/O-bound. **W skrócie:** - Pozwala efektywnie obsługiwać wiele operacji I/O. - Opiera się na `async` i `await`. - Dobrze nadaje się do usług i klientów sieciowych.
242. Czym różni się programowanie synchroniczne od asynchronicznego w Pythonie? #### Python Programowanie synchroniczne oznacza, że wywołanie blokuje bieżący wątek do zakończenia. Programowanie asynchroniczne oznacza, że `await` oddaje sterowanie pętli zdarzeń, gdy operacja czeka na I/O. **W skrócie:** - Async zmniejsza czas bezczynności podczas I/O. - Sync jest prostszy dla logiki liniowej. - Async dodaje złożoność zarządzania zadaniami i anulowaniem.
243. Czym są `async` i `await`? #### Python `async def` definiuje funkcję typu coroutine. `await` wstrzymuje coroutine do gotowości obiektu awaitable i oddaje sterowanie pętli. **W skrócie:** - To składnia asynchronicznego modelu kooperatywnego. - Używa się jej razem z `asyncio` i bibliotekami asynchronicznymi. - `await` można stosować tylko wewnątrz `async def`.
244. Jak działa `asyncio`? #### Python `asyncio` uruchamia pętlę zdarzeń, która wykonuje zadania, czyli coroutines, przełączając się w punktach `await` i planując gotowe operacje I/O. **Krytyczna zasada:** Pętla zdarzeń działa w jednym wątku. Każda blokująca operacja, taka jak `time.sleep()`, synchroniczne żądania `requests` albo ciężkie obliczenia, zatrzymuje **całą** pętlę i wszystkie inne zadania. **W skrócie:** - Jeden wątek może obsługiwać wiele zadań I/O dzięki kooperatywności. - Planowanie nie wywłaszcza zadań, czyli jest niewywłaszczające. - Blokujące wywołania niszczą wydajność `asyncio`.
245. Czym jest pętla zdarzeń? #### Python Pętla zdarzeń to planista, który śledzi zdarzenia oraz gotowość I/O i uruchamia odpowiednie funkcje zwrotne oraz coroutines. **W skrócie:** - To centralny komponent modelu `asyncio`. - Zarządza cyklem życia zadań asynchronicznych. - Określa, kiedy dana coroutine ma wznowić wykonanie.
246. Jak `asyncio` pozwala realizować programowanie asynchroniczne i jakie główne komponenty biorą udział w kodzie `asyncio`? #### Python Kluczowe komponenty: - pętla zdarzeń; - coroutine, czyli `async def`; - task, czyli `asyncio.create_task`; - awaitables, czyli futures, tasks i coroutines; - prymitywy synchronizacji, takie jak `Lock`, `Queue`, `Semaphore`. **W skrócie:** - `asyncio` łączy planowanie i asynchroniczne API w jeden model. - Zadania kooperatywnie współdzielą jeden wątek wykonania. - Architektura powinna uwzględniać timeouty, ponawianie i anulowanie.
247. Kiedy `asyncio` nie daje korzyści? #### Python Gdy obciążenie jest CPU-bound albo główne biblioteki są blokujące i nie mają API asynchronicznego. Nie opłaca się też w prostych krótkich skryptach. **Rozwiązanie dla blokującego kodu:** Jeśli trzeba użyć biblioteki blokującej w środowisku asynchronicznym, można użyć `loop.run_in_executor(None, sync_func)`, aby uruchomić ją w osobnym wątku i nie blokować pętli zdarzeń. **W skrócie:** - Async nie przyspiesza czystych obliczeń. - Bez nieblokujących bibliotek I/O korzyść jest minimalna. - `run_in_executor` pomaga integrować starszy kod synchroniczny. - Złożoność podejścia asynchronicznego powinna być uzasadniona obciążeniem.
248. Jak działa anulowanie w `asyncio`? #### Python Anulowanie zadania przez `task.cancel()` podnosi `CancelledError` w coroutine. Kod powinien poprawnie obsługiwać czyszczenie w `try/finally`. **W skrócie:** - Anulowanie jest zwykłym przepływem sterowania w async. - Obsługę anulowania trzeba uwzględniać w projekcie coroutine. - Ignorowanie anulowania prowadzi do "zawieszonych" zadań.
249. Czym jest `contextvars`? #### Python `contextvars` daje zmienne lokalne dla kontekstu, bezpieczne w scenariuszach asynchronicznych i wielowątkowych. Przydaje się dla request-id, correlation-id i kontekstu tenantów. **W skrócie:** - To alternatywa dla globalnego stanu w kodzie współbieżnym. - Wartość jest izolowana w ramach kontekstu. - Poprawia śledzenie i obserwowalność.
250. Jakie najlepsze praktyki warto stosować przy pisaniu kodu w Pythonie? #### Python - przestrzegać PEP 8 i automatyzować formatowanie; - pisać jawne adnotacje typów dla publicznego API; - używać `with` do pracy z zasobami; - pokrywać logikę biznesową testami; - unikać przedwczesnej optymalizacji i profilować; - trzymać moduły niewielkie i o jasnej odpowiedzialności; - zarządzać zależnościami przez `pyproject.toml` i strategię lock. **W skrócie:** - Czytelność i przewidywalność są ważniejsze niż "sztuczki". - Jakość opiera się na automatyzacji: lint, typy, testy i CI. - Prostota architektury zmniejsza koszt utrzymania.