Python 유형 힌트: 반공변, 공변, 불변
그렇다면 공변량이란 무엇입니까?
A<: B이면 어디에서나 B를 A로 바꿀 수 있습니다.
여기서 B에 결합된 T는 C[T]라고 합니다.
A <: B => C[A] :> C[B]
어디에서나 C[B]를 C[A]로 바꿀 수 있습니다. A <: B => C[A] <: C[B]
어디에서나 C[A]를 C[B]로 바꿀 수 있습니다. 그러나이 상황을 일으키는 방법은 무엇입니까? 아래 예제 코드에서 설명하겠습니다. Sink / Source와 개념을 결합하십시오.
그들의 행동에 따라 우리는 두 종류의 객체를 정의했습니다.
매우 추상적이므로 아래 코드로 바로 넘어갑니다. 의견에 따라 수정하여 실험해 보십시오.
import abc
from typing import Generic, TypeVar
class Base:
def foo(self):
print("foo")
class Derived(Base):
def bar(self):
print("bar")
먼저
Base
와 Derived.
Derived
가 Base,
에 내재되어 있으므로 Derived <: Base.
T_co = TypeVar('T_co', bound='Base', covariant=True)
class Source(Generic[T_co]):
@abc.abstractmethod
def generate(self) -> T_co: # Produce T_co!
pass
class SourceBase(Source[Base]):
def generate(self) -> Derived: # Produce T_co!
return Derived()
class SourceDerived(Source[Derived]):
def generate(self) -> Derived:
return Derived()
source: Source[Base] = SourceDerived()
source.generate()
#Try to uncomment lines below.
#source_derived: Source[Derived] = SourceBase()
#source_derived.generate()
이제
SourceDerived <: SourceBase
가 있습니다. covariant=True
를 제거하면 다음 경고가 표시됩니다.[Pyright reportGeneralTypeIssues] [E] Expression of type > "SourceDerived" cannot be assigned to declared type "Source[Base]"
TypeVar "T_co@Source" is invariant
"Derived" is incompatible with "Base"
covariant
를 contravariant,
로 수정하면 이렇게 됩니다. covariant
검사기 SourceDerived는 SourceBase를 사용하는 모든 곳에서 안전하게 사용할 수 있음을 알려줍니다. def generate(self) -> T_co: <- warining
pass
warining: [Pyright reportGeneralTypeIssues] [E] Contravariant type variable cannot be used in return type
TypeVar "T_co@Source" is contravariant
covariant
처럼 C[T_co]를 사용하는 곳을 확인하는 것 뿐만 아니라 C[T_co]에서 T_co를 반환하는 메서드를 확인하는 방법도 있습니다.다음으로
contravariant
예제를 살펴보겠습니다.T_contra = TypeVar('T_contra', bound='Base', contravariant=True)
class Sink(Generic[T_contra]):
@abc.abstractmethod
def consume(self, value: T_contra):
pass
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):
pass
base = Base()
derived = Derived()
sink_derived: Sink[Derived] = SinkBase()
#we can safely consumer
sink_derived.consume(base)
sink_derived.consume(derived)
#Try to uncomment this line.
#sink_derived.other_func()
여기에
SinkDerive <: SinkBase
가 있습니다. 제거contravariant=True
하면 경고가 표시됩니다.[Pyright reportGeneralTypeIssues] [E] Expression of type "SinkBase" cannot be assigned to declared type > "Sink[Derived]"
TypeVar "T_contra@Sink" is invariant
"Base" is incompatible with "Derived"
contravariant=True
정적 검사기에 Base를 Base 또는 Derive 유형으로 안전하게 사용할 수 있음을 알려줍니다. T_contra가 반공변이라는 주석을 달았지만 예를 들어 Sink[Derived]sink_derived.other_func()
메서드를 호출하면 오류가 발생합니다. 그럼에도 불구하고 contravariant
가 covariant.
와 반대라고 가정하는 것이 일반적입니다.대부분의 상황에서
contravariant
또는 covariant
를 바로 추가할 필요가 없다고 생각합니다. 검사기가 불평할 때만 적절하게 사용되는 경우 이러한 제네릭 유형의 관계를 자세히 살펴봅니다. 그렇다면 이러한 힌트를 추가하는 것을 고려합니다.
Reference
이 문제에 관하여(Python 유형 힌트: 반공변, 공변, 불변), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/daniel1in/python-type-hint-contravariant-covariant-invariant-15lj텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)