Interpretowany, wysokopoziomowy język ogólnego przeznaczenia. Dynamicznie typowany, garbage-collected.
| Paradygmat | Opis |
|---|---|
| OOP | klasy, dziedziczenie, enkapsulacja, polimorfizm |
| Proceduralne | sekwencja instrukcji, funkcje |
| Funkcyjne | lambda, map/filter/reduce, closures |
| Aspektowe | dekoratory |
import this — 19 zasad projektowych Pythona
Mutex w CPython który pozwala tylko jednemu wątkowi na raz wykonywać Python bytecode.
# CPU-bound → multiprocessing from multiprocessing import Pool # I/O-bound → asyncio import asyncio
| Typ | Przykład | Uwagi |
|---|---|---|
| int | 42, -7, 0xFF, 0b101 | nieograniczona precyzja |
| float | 3.14, 1e-10, inf | IEEE 754 double |
| complex | 3+2j | część rzeczywista + urojona |
| Decimal | Decimal('0.1') | dokładna arytmetyka |
| Fraction | Fraction(1,3) | ułamki |
# operatory 7 // 2 # 3 — dzielenie całkowite 7 % 2 # 1 — modulo 2 ** 8 # 256 — potęgowanie abs(-5) # 5 round(3.567, 2) # 3.57
Niemutowalny ciąg znaków Unicode. Indeksowany od 0.
# tworzenie s = 'hello' s = "hello" s = """wieloliniowy string""" s = r'\n nie escape' # raw s = f'wynik: {2+2}' # f-string s = b'bajty' # bytes # operacje s[0] # 'h' s[-1] # ostatni s[1:3] # slice 'el' s[::-1] # odwrócony len(s) # długość s.upper() s.lower() s.strip() s.split(',') s.replace('a','b') s.startswith('h') ','.join(['a','b']) # 'a,b' 'sub' in s # bool
# bool (podklasa int!) True False bool(0) # False bool('') # False bool([]) # False bool(1) # True # Falsy: 0, '', [], {}, (), None, set() # Truthy: wszystko inne # None — brak wartości x = None x is None # True (używaj 'is' nie ==) # operatory logiczne and or not # short-circuit evaluation! x = x or 'default'
Opcjonalne adnotacje typów — nie wymuszane w runtime, ale pomagają IDE i mypy.
def greet(name: str) -> str: return f'Cześć {name}' x: int = 5 y: list[int] = [1, 2, 3] from typing import Optional, Union z: Optional[str] = None # str | None w: Union[int, str] = 5 # int | str (3.10+)
a = [1, 2, 3] a.append(4) # [1,2,3,4] a.extend([5,6]) # dodaj wiele a.insert(0, 99) # wstaw na indeks a.pop() # usuń ostatni a.pop(0) # usuń z indeksu a.remove(2) # usuń wartość a.sort() # in-place sorted(a) # nowa lista a.reverse() a[1:3] = [9,9] # slice assignment # list comprehension sq = [x**2 for x in range(10) if x % 2 == 0]
t = (1, 2, 3) t = 1, 2, 3 # bez nawiasów też działa t = (1,) # jednoelementowy — uwaga na ',' # unpacking a, b, c = t a, *rest = t # star unpacking # namedtuple from collections import namedtuple Point = namedtuple('Point', ['x', 'y']) p = Point(1, 2) p.x # 1 # tuple szybszy niż list, hashable → może być kluczem dict
d = {'a': 1, 'b': 2}
d['c'] = 3
d.get('x', 0) # default jeśli brak
d.keys()
d.values()
d.items() # (k,v) pary
d.update({'d':4})
d.pop('a')
'a' in d # sprawdź klucz
# merge (3.9+)
merged = d1 | d2
d1 |= d2
# dict comprehension
sq = {k: v**2 for k,v in d.items()}
# defaultdict
from collections import defaultdict
dd = defaultdict(list)
s = {1, 2, 3}
s = set([1,2,2,3]) # {1,2,3}
s.add(4)
s.discard(2) # bez błędu jeśli brak
s.remove(2) # KeyError jeśli brak
# operacje zbiorowe
a | b # suma (union)
a & b # iloczyn (intersection)
a - b # różnica
a ^ b # różnica symetryczna
a <= b # podzbiór
# frozenset — niemutowalny, hashable
fs = frozenset({1,2,3})
from collections import ( Counter, deque, OrderedDict, defaultdict, ChainMap ) # Counter — zliczanie c = Counter('abracadabra') c.most_common(3) # deque — kolejka O(1) append/pop obu stron dq = deque(maxlen=100) dq.appendleft(0) dq.rotate(1) # ChainMap — wiele dict jako jeden cm = ChainMap(d1, d2)
def add(a: int, b: int = 0) -> int: """Docstring — opis funkcji.""" return a + b # *args — dowolna liczba pozycyjnych def suma(*args): return sum(args) # **kwargs — dowolna liczba nazwanych def info(**kwargs): for k, v in kwargs.items(): print(f'{k}: {v}') # keyword-only (po *) def f(a, *, b, c=1): pass # positional-only (przed /) def g(a, b, /, c): pass
# lambda — anonimowa, jednolinijkowa sq = lambda x: x ** 2 sq(5) # 25 # map, filter, reduce list(map(lambda x: x*2, [1,2,3])) list(filter(lambda x: x>2, [1,2,3])) from functools import reduce reduce(lambda a,b: a+b, [1,2,3]) # sorted z kluczem sorted(items, key=lambda x: x.age) # partial from functools import partial double = partial(mul, 2)
# dekorator — funkcja opakowująca funkcję def moj_dekorator(func): def wrapper(*args, **kwargs): print('przed') wynik = func(*args, **kwargs) print('po') return wynik return wrapper @moj_dekorator def hello(): print('hello') # wbudowane dekoratory @staticmethod # bez self @classmethod # cls zamiast self @property # getter jak atrybut # functools.wraps — zachowuje metadane from functools import wraps, lru_cache @lru_cache(maxsize=128) # memoizacja! def fib(n): return n if n<2 else fib(n-1)+fib(n-2)
Leniwe sekwencje — nie ładują wszystkiego do pamięci naraz.
# generator function (yield) def squares(n): for i in range(n): yield i ** 2 for sq in squares(5): print(sq) # generator expression (jak comprehension) gen = (x**2 for x in range(1000000)) next(gen) # jeden na raz # yield from — deleguj do pod-generatora def flatten(lst): for item in lst: if isinstance(item, list): yield from flatten(item) else: yield item
Python szuka nazw w kolejności: Local → Enclosing → Global → Built-in
# closure def counter(start=0): count = [start] def inc(): count[0] += 1 return count[0] return inc # nonlocal — modyfikuj zmienną z enclosing def outer(): x = 10 def inner(): nonlocal x x += 1 inner() # global — modyfikuj zmienną globalną g = 0 def f(): global g; g += 1
class Animal: # atrybut klasy (współdzielony) kingdom = 'Animalia' def __init__(self, name: str, age: int): self.name = name # atrybut instancji self._age = age # _ = konwencja "prywatny" self.__secret = 'X' # __ = name mangling def speak(self) -> str: # metoda instancji return f'I am {self.name}' @property def age(self): return self._age @age.setter def age(self, v): if v < 0: raise ValueError self._age = v @classmethod def create(cls, name): return cls(name, 0) @staticmethod def is_animal(obj): return isinstance(obj, Animal) def __repr__(self): return f'Animal({self.name!r})' def __str__(self): return self.name def __eq__(self, o): return self.name == o.name def __len__(self): return self._age class Dog(Animal): # dziedziczenie def speak(self): return 'Woof!' # override def fetch(self): super().speak() # wywołaj rodzica
| Metoda | Kiedy wywoływana |
|---|---|
| __init__ | konstruktor (tworzenie obiektu) |
| __repr__ | repr(obj) — developerski opis |
| __str__ | str(obj), print(obj) |
| __len__ | len(obj) |
| __getitem__ | obj[key] |
| __setitem__ | obj[key] = val |
| __contains__ | x in obj |
| __iter__ | for x in obj |
| __call__ | obj() |
| __enter__/__exit__ | with obj: |
| __add__/__mul__ | obj + other |
| __eq__/__lt__ | ==, < |
| __hash__ | hash(obj), dict key |
from dataclasses import dataclass, field @dataclass class Point: x: float y: float z: float = 0.0 tags: list = field(default_factory=list) # auto: __init__, __repr__, __eq__ @dataclass(frozen=True) # niemutowalny class Frozen: x: int # Klasa abstrakcyjna from abc import ABC, abstractmethod class Shape(ABC): @abstractmethod def area(self) -> float: ... class Circle(Shape): def __init__(self, r): self.r = r def area(self): return 3.14 * self.r**2
# if / elif / else if x > 0: ... elif x == 0: ... else: ... # ternary val = 'tak' if x > 0 else 'nie' # match/case (3.10+) match command: case 'quit': ... case 'go', direction: ... case _: ... # wildcard # for for i in range(10): ... for i, v in enumerate(lst): ... for a, b in zip(l1, l2): ... else: ... # wykonuje się jeśli brak break # while while condition: if bad: break if skip: continue
try: risky() except ValueError as e: print(e) except (TypeError, KeyError): print('kilka typów') except Exception: # łapie prawie wszystko raise # ponownie rzuć else: # jeśli NIE było wyjątku ok() finally: # zawsze cleanup() # własny wyjątek class AppError(Exception): def __init__(self, msg, code): super().__init__(msg) self.code = code raise AppError('błąd', 404)
# with — auto cleanup with open('plik.txt', 'r', encoding='utf-8') as f: data = f.read() # własny context manager class Timer: def __enter__(self): self.start = time.time() return self def __exit__(self, *args): print(time.time() - self.start) # lub dekoratorem from contextlib import contextmanager @contextmanager def managed(): setup() yield cleanup()
import asyncio async def fetch(url): await asyncio.sleep(1) # non-blocking return 'data' async def main(): # równolegle r1, r2 = await asyncio.gather( fetch('url1'), fetch('url2') ) asyncio.run(main()) # async generator async def stream(): for i in range(5): await asyncio.sleep(0.1) yield i
| Funkcja | Co robi |
|---|---|
| len(x) | długość |
| range(n) | sekwencja liczb |
| enumerate(it) | indeks + wartość |
| zip(a, b) | pary elementów |
| map(f, it) | zastosuj funkcję |
| filter(f, it) | filtruj |
| sorted(it) | posortowana kopia |
| reversed(it) | odwrócony iterator |
| any(it) / all(it) | bool na kolekcji |
| min/max/sum | agregaty |
| isinstance(o, T) | sprawdź typ |
| hasattr/getattr/setattr | atrybuty obiektu |
| dir(obj) | lista atrybutów |
| vars(obj) | __dict__ obiektu |
| id(obj) | adres w pamięci |
| hash(obj) | hash value |
| open() | plik |
| input() | wejście od użytkownika |
| Moduł | Do czego |
|---|---|
| os / pathlib | system plików |
| sys | interpreter, argv |
| json | JSON encode/decode |
| re | wyrażenia regularne |
| datetime | daty i czas |
| math / statistics | obliczenia |
| random | losowość |
| itertools | kombinatoryka iteratorów |
| functools | HOF, caching, partial |
| threading | wątki (I/O-bound) |
| multiprocessing | procesy (CPU-bound) |
| asyncio | async I/O |
| subprocess | uruchom proces zewnętrzny |
| logging | logi |
| unittest / pytest | testy |
| typing | type hints |
| dataclasses | klasy danych |
| enum | enumeracje |
| abc | klasy abstrakcyjne |
int('42') # str → int int('FF', 16) # hex → int float('3.14') # str → float str(42) # → str bool(0) # → False list({1,2}) # set → list tuple([1,2]) # list → tuple set([1,1,2]) # list → set (usuwa duplikaty) dict([('a',1)]) # list par → dict chr(65) # 'A' ord('A') # 65 hex(255) # '0xff' bin(10) # '0b1010'
"If it walks like a duck..." — Python sprawdza metody, nie typy.
# Iterable: __iter__ # Iterator: __iter__ + __next__ # Sequence: __getitem__ + __len__ # Mapping: __getitem__ + __len__ + __iter__ # Callable: __call__ # Context Manager: __enter__ + __exit__ # typing.Protocol (3.8+) from typing import Protocol class Drawable(Protocol): def draw(self) -> None: ...
# list comprehension [x**2 for x in range(10)] # dict comprehension {k: v for k, v in d.items() if v} # set comprehension {x % 3 for x in range(10)} # generator expression (leniwy) (line.strip() for line in file) # zagnieżdżone flat = [x for row in matrix for x in row] # walrus operator (3.8+) if (n := len(data)) > 100: print(f'długi: {n}') filtered = [y := f(x), y**2]
# importy import os import os.path as osp from pathlib import Path from . import modul # relatywny from .. import coś # poziom wyżej # __name__ if __name__ == '__main__': main() # __all__ — eksportuj z modułu __all__ = ['MyClass', 'my_func'] # struktura pakietu # mypackage/ # __init__.py # module.py # subpkg/__init__.py
# venv python3 -m venv .venv source .venv/bin/activate # Linux/Mac .venv\Scripts\activate # Windows # pip pip install requests pip freeze > requirements.txt pip install -r requirements.txt # pyproject.toml (nowoczesne) # [project] # name = "myapp" # dependencies = ["requests"] # Popularne narzędzia: # uv — szybszy pip/venv # poetry — zarządzanie zależnościami # pyenv — wiele wersji Python # ruff — szybki linter/formatter # mypy — statyczne typowanie
# __slots__ — oszczędność pamięci class Point: __slots__ = ['x', 'y'] # brak __dict__! def __init__(self, x, y): self.x = x; self.y = y # Metaklasa — klasa klas class Meta(type): def __new__(mcs, name, bases, ns): return super().__new__(mcs, name, bases, ns) class MyClass(metaclass=Meta): pass # Descriptor protocol class Validator: def __get__(self, obj, t): ... def __set__(self, obj, val): ... def __delete__(self, obj): ...
# Singleton class Singleton: _inst = None def __new__(cls): if not cls._inst: cls._inst = super().__new__(cls) return cls._inst # Dependency Injection def process(data, logger=None): logger = logger or print logger('processing') # Registry _registry = {} def register(name): def dec(cls): _registry[name] = cls return cls return dec