Python: TypeVar covariance contravariance invariance

发布时间 2023-04-24 16:37:51作者: ascertain

 

contra-variance

from typing import Callable


class Food:
    ...


class Meat(Food):
    ...


class Animal:
    def eat(self, food: Food):
        ...


class Dog(Animal):
    def eat(self, food: Food):
        ...

    def dog(self):
        print('Dog', self)


a: Animal = Animal()
d: Dog = Dog()


def animal_run(animal: Animal) -> None:  # Callable[[Animal], None]
    print('An animal is running!')


def dog_run(dog: Dog) -> None:  # Callable[[Dog], None]
    print('A dog is running!')
    dog.dog()


animal_run(a)
dog_run(d)

# Dog <: Animal
# Callable[[Animal], None] <: Callable[[Dog], None]  contra-variance


def make_dog_run(dog: Dog, run_function: Callable[[Dog], None]) -> None:
    run_function(dog)


lassie: Dog = Dog()
make_dog_run(dog=lassie, run_function=animal_run)
make_dog_run(dog=lassie, run_function=dog_run)

 

https://dev.to/daniel1in/python-type-hint-contravariant-covariant-invariant-15lj

 

 

 

 

 

from abc import ABCMeta, abstractmethod
from typing import TypeVar, Generic


class Base:
    def foo(self):
        print('foo')


class Derived(Base):
    def bar(self):
        print('bar')


T_contra = TypeVar('T_contra', bound=Base, covariant=True, contravariant=False)


class Sink(Generic[T_contra]):
    @abstractmethod
    def consume(self, value: T_contra):
        ...


class SinkBase(Sink[Base]):
    def consume(self, value: Base):
        value.foo()


class SinkDerived(Sink[Derived]):
    def consume(self, value: Derived):
        value.bar()

    def other_func(self):
        ...


base = Base()
derived = Derived()

sink_base: Sink[Base] = SinkDerived()
sink_derived: Sink[Derived] = SinkBase()


class Source(Generic[T_contra]):
    @abstractmethod
    def generate(self) -> T_contra:
        ...


class SourceBase(Source[Base]):
    def generate(self) -> Derived:
        return Derived()


class SourceDerived(Source[Derived]):
    def generate(self) -> Derived:
        return Derived()


source: Source[Base] = SourceDerived()
source.generate()

source_derived: Source[Derived] = SourceBase()
source_derived.generate()

 

 

 

 

 

https://blog.daftcode.pl/covariance-contravariance-and-invariance-the-ultimate-python-guide-8fabc0c24278