0Pricing
Python Academy · Lekcja

TypeVar, klasy generyczne i Protocol

Proszę definiować wielokrotnego użytku typy generyczne oraz podtypowanie strukturalne za pomocą Protocol.

TypeVar, klasy generyczne i Protocol to bezpłatna lekcja Python Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Python Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Python Academy zawiera 4 lekcji w sumie.

Czym jest TypeVar

TypeVar deklaruje zmienną typu — symbol zastępczy, który może reprezentować dowolny typ, w razie potrzeby ograniczony określonymi warunkami. Jest używany w funkcjach i klasach generycznych.

from typing import TypeVar

T = TypeVar("T")

def identity(value: T) -> T:
    return value

print(identity(42))      # int
print(identity("hello")) # str

Funkcje generyczne

Funkcja używająca TypeVar zarówno w typach parametrów, jak i wartości zwracanej pozwala narzędziu mypy wywnioskować typ zwracany na podstawie typu argumentu.

from typing import TypeVar

T = TypeVar("T")

def first(items: list[T]) -> T:
    return items[0]

x: int = first([1, 2, 3])     # mypy knows x is int
s: str = first(["a","b","c"]) # mypy knows s is str

Ograniczony TypeVar

Należy przekazać ograniczenia typów do TypeVar, aby ograniczyć zbiór akceptowanych typów.

from typing import TypeVar

Numeric = TypeVar("Numeric", int, float)

def double(n: Numeric) -> Numeric:
    return n * 2

print(double(5))    # 10
print(double(2.5))  # 5.0
# double("x")  # mypy error

Klasy generyczne

Należy dziedziczyć po Generic[T], aby utworzyć klasę parametryzowaną zmienną typu.

from typing import Generic, TypeVar

T = TypeVar("T")

class Stack(Generic[T]):
    def __init__(self) -> None:
        self._items: list[T] = []

    def push(self, item: T) -> None:
        self._items.append(item)

    def pop(self) -> T:
        return self._items.pop()

stack: Stack[int] = Stack()
stack.push(1)
print(stack.pop())   # 1

Wiele zmiennych TypeVar

Należy użyć wielu zmiennych TypeVar, aby parametryzować klasę lub funkcję za pomocą dwóch niezależnych typów.

from typing import Generic, TypeVar

K = TypeVar("K")
V = TypeVar("V")

class Pair(Generic[K, V]):
    def __init__(self, key: K, value: V) -> None:
        self.key = key
        self.value = value

p: Pair[str, int] = Pair("age", 30)
print(p.key, p.value)   # age 30

Protocol — podtypowanie strukturalne

Protocol definiuje interfejs na podstawie metod i atrybutów, które musi zawierać klasa, bez wymagania jawnego dziedziczenia (sprawdzany przez system typów „duck typing”).

from typing import Protocol

class Drawable(Protocol):
    def draw(self) -> None: ...

def render(obj: Drawable) -> None:
    obj.draw()

class Circle:
    def draw(self) -> None:
        print("Drawing circle")

render(Circle())   # works — Circle satisfies Drawable

Protocol z runtime_checkable

Należy dodać @runtime_checkable do Protocol, aby włączyć sprawdzanie isinstance() w czasie wykonywania.

from typing import Protocol, runtime_checkable

@runtime_checkable
class Closeable(Protocol):
    def close(self) -> None: ...

class File:
    def close(self) -> None: print("closed")

print(isinstance(File(), Closeable))   # True

Protocol a ABC

ABC wymagają jawnego dziedziczenia (class Dog(Animal)). Protocol działają na podstawie dopasowania strukturalnego — jeśli klasa ma właściwe metody, spełnia wymagania protokołu niezależnie od dziedziczenia.

from typing import Protocol
from abc import ABC, abstractmethod

# ABC: nominal typing
class Printable(ABC):
    @abstractmethod
    def display(self) -> None: ...

# Protocol: structural typing
class Displayable(Protocol):
    def display(self) -> None: ...

TypeVar z bound

TypeVar("T", bound=BaseClass) ogranicza T do BaseClass lub dowolnej z jej klas potomnych.

from typing import TypeVar

class Animal:
    def speak(self) -> str: return "..."

A = TypeVar("A", bound=Animal)

def make_speak(animal: A) -> str:
    return animal.speak()

Alias generyczny — Python 3.12

Python 3.12 wprowadza instrukcję type do zwięzłego definiowania aliasów typów oraz składnię class Foo[T] dla typów generycznych bez importowania TypeVar.

# Python 3.12+
type Vector = list[float]
type Matrix = list[Vector]

class Stack[T]:
    def __init__(self) -> None: self._items: list[T] = []
    def push(self, item: T) -> None: self._items.append(item)
    def pop(self) -> T: return self._items.pop()

Typ Self

Self (z modułu typing w wersji 3.11+) służy do opisywania metod, które zwracają bieżącą klasę; jest przydatny w interfejsach fluent i klasach potomnych.

from typing import Self

class Builder:
    def __init__(self) -> None:
        self.parts: list[str] = []

    def add(self, part: str) -> Self:
        self.parts.append(part)
        return self

b = Builder().add("a").add("b")
print(b.parts)   # ["a", "b"]

Szybkie sprawdzenie

Jaka jest najważniejsza różnica między Protocol a ABC w systemie typów Pythona?

Podsumowanie

TypeVar tworzy symbole zastępcze typów dla funkcji i klas generycznych. Generic[T] parametryzuje klasy. Protocol umożliwia podtypowanie strukturalne bez dziedziczenia. Należy używać bound= lub ograniczeń typów w TypeVar, aby ograniczyć akceptowane typy.

Często zadawane pytania

Czy lekcja „TypeVar, klasy generyczne i Protocol” jest bezpłatna?

Tak — pełny tekst „TypeVar, klasy generyczne i Protocol” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Python Academy, przejdź na CoddyKit PRO. Kurs Python Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „TypeVar, klasy generyczne i Protocol”?

Proszę definiować wielokrotnego użytku typy generyczne oraz podtypowanie strukturalne za pomocą Protocol. Ćwiczysz Python Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Python Academy?

Nie wymagamy żadnego doświadczenia. Python Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.

Ile czasu zajmuje lekcja „TypeVar, klasy generyczne i Protocol”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Python Academy?

Tak. Każda lekcja Python Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Podstawowe adnotacje typów
  2. Typy złożone: List, Dict, Optional, Union
  3. TypeVar, klasy generyczne i Protocol
  4. Uruchamianie mypy i naprawianie błędów typów
← Powrót do Python Academy