Python Academy · Oppitunti

TypeVar, geneeriset luokat ja Protocol

Määrittäkää uudelleenkäytettäviä geneerisiä tyyppejä ja rakenteellista alityypitystä Protocolin avulla.

Oppitunti 3/413 vaihetta

TypeVar, geneeriset luokat ja Protocol on ilmainen Python Academy-oppitunti CoddyKitissä. Tämä on oppitunti 3/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Python Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Python Academy-kurssilla on yhteensä 4 oppituntia.

Mikä on TypeVar

TypeVar määrittää tyyppimuuttujan eli paikanhaltijan, joka voi olla mikä tahansa tyyppi ja jota voidaan tarvittaessa rajoittaa. Sitä käytetään geneerisissä funktioissa ja luokissa.

from typing import TypeVar

T = TypeVar("T")

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

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

Geneeriset funktiot

Kun funktio käyttää TypeVar-muuttujaa sekä parametri- että paluutyypeissä, mypy voi päätellä paluutyypin argumentin tyypin perusteella.

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

Rajoitettu TypeVar

Välittäkää tyyppirajoitteet TypeVar-kutsulle rajoittaaksenne hyväksyttäviä tyyppejä.

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

Geneeriset luokat

Perikää luokka Generic[T]-luokasta luodaksenne tyyppimuuttujalla parametrisoidun luokan.

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

Useita TypeVar-muuttujia

Käyttäkää useita TypeVar-muuttujia parametrisoidaksenne luokan tai funktion kahdella toisistaan riippumattomalla tyypillä.

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 — rakenteellinen alityypitys

Protocol määrittää rajapinnan luokan edellyttämien metodien ja attribuuttien avulla ilman nimenomaista perintää ("duck typing", tyyppitarkistettu).

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 ja runtime_checkable

Lisätkää @runtime_checkable Protocol-määrittelyyn, jotta isinstance()-tarkistukset voidaan tehdä ajonaikaisesti.

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 ja ABC

ABC:t edellyttävät nimenomaista perintää (class Dog(Animal)). Protokollat toimivat rakenteellisen yhteensopivuuden perusteella: jos luokalla on oikeat metodit, se täyttää protokollan perinnästä riippumatta.

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 ja bound

TypeVar("T", bound=BaseClass) rajoittaa T:n BaseClass-luokkaan tai mihin tahansa sen aliluokkaan.

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()

Geneerinen alias — Python 3.12

Python 3.12 esittelee type-lauseen selkeiden tyyppialiasten määrittämiseen sekä geneerisen syntaksin class Foo[T] ilman TypeVar-muuttujan tuontia.

# 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()

Self-tyyppi

Self (typing-moduulista versiosta 3.11 alkaen) merkitsee nykyisen luokan palauttavat metodit, mikä on hyödyllistä sujuvissa rajapinnoissa ja aliluokissa.

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"]

Pikatarkistus

Mikä on Protocolin ja ABC:n keskeinen ero Pythonin tyypityksessä?

Kertaus

TypeVar luo tyyppipaikanhaltijoita geneerisille funktioille ja luokille. Generic[T] parametrisoi luokkia. Protocol mahdollistaa rakenteellisen alityypityksen ilman perintää. Käyttäkää bound=-rajoitetta tai tyyppirajoitteita TypeVar-muuttujissa hyväksyttävien tyyppien rajaamiseen.

Aloita maksutta

Opi Python tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
76
Oppitunnit
320

Usein kysytyt kysymykset

Onko oppitunti ”TypeVar, geneeriset luokat ja Protocol” ilmainen?

Kyllä – oppitunnin ”TypeVar, geneeriset luokat ja Protocol” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Python Academy-kurssin, päivitä CoddyKit PROhon. Python Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”TypeVar, geneeriset luokat ja Protocol”?

Määrittäkää uudelleenkäytettäviä geneerisiä tyyppejä ja rakenteellista alityypitystä Protocolin avulla. Harjoittelet Python Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Python Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Python Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 3/4.

Kuinka kauan ”TypeVar, geneeriset luokat ja Protocol”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Python Academy-oppitunnilla?

Kyllä. Jokainen Python Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Tyyppimerkintöjen perusteet
  2. Monimutkaiset tyypit: List, Dict, Optional, Union
  3. TypeVar, geneeriset luokat ja Protocol
  4. mypyn suorittaminen ja tyyppivirheiden korjaaminen
← Takaisin: Python Academy