Я хочу создать эквивалент этого в Python:
static class Event {}
static class MyEvent extends Event {}
interface Filter<E extends Event> {
boolean filter(E event);
}
static class MyFilter implements Filter<MyEvent> {
@Override public boolean filter(MyEvent event) {
return true;
}
}
Это моя попытка (mypy-play):
from typing import TypeVar, Protocol
class Event:
pass
class MyEvent(Event):
pass
E = TypeVar("E", bound=Event)
class Filter(Protocol[E]):
def filter(self, event: E) -> bool:
raise NotImplementedError
class MyFilter(Filter):
def filter(self, event: MyEvent) -> bool: # should be ok
raise NotImplementedError
class BadFilter(Filter):
def filter(self, event: object) -> bool: # should fail
raise NotImplementedError
... это не удается с main.py:11: error: Invariant type variable 'E' used in protocol where contravariant one is expected
. Если я не ошибаюсь, Java, кажется, подходит для инвариантного, и это тоже моя идея; Я не хочу, чтобы различные Filter
были совместимы друг с другом. В любом случае, наложение contravariant=True
на T
не работать либо. Так,
Зачем протоколу нужна контравариантная переменная? И как мне сделать эту проверку типа кода Python?
1 ответ
Протоколы этого не допускают, потому что это нарушает транзитивность подтипа. См. PEP 544.
Если у вас есть следующие два класса:
class A:
def method(self, arg: int):
pass
class B(A):
def method(self, arg: object):
pass
Тогда B
является допустимым подклассом A
, потому что B.method
может принимать любые аргументы, которые могут A.method
. Однако, если бы вы могли ввести следующий протокол:
T = typing.TypeVar('T')
class Proto(typing.Protocol[T]):
def method(self, arg: T):
pass
Тогда A
удовлетворяло бы Proto[int]
, но B
не удовлетворяло бы из-за инвариантности T
.
A
явно реализовывал протокол, создание подкласса было бы ошибкой, и эта проблема не возникла бы. Думаю, я хочу либо использовать что-то другое, чем Protocol
, либо вместо этого использовать контравариант TypeVar
. Это моя последняя последняя попытка — хорошо выглядит?
foo: Filter = BadFilter2()
проходит, потому что Foo
интерпретируется как Foo[Any]
, а Any
в основном относится к типу "не проверять меня". Это похоже на использование необработанных типов в Java.
Filter[Any]
вместо Filter[E]
, как было определено? Я не уверен, что это работает в Java, поскольку Java требует явного объявления интерфейсов и просто не позволит мне сделать что-то вроде BadFilter2
Похожие вопросы
Связанные вопросы
Новые вопросы
python
Python — это мультипарадигмальный многоцелевой язык программирования с динамической типизацией. Он предназначен для быстрого изучения, понимания и использования, а также обеспечивает чистый и унифицированный синтаксис. Обратите внимание, что Python 2 официально не поддерживается с 01.01.2020. Если у вас есть вопросы о версии Python, добавьте тег [python-2.7] или [python-3.x]. При использовании варианта Python (например, Jython, PyPy) или библиотеки (например, Pandas, NumPy) укажите это в тегах.
BadFilter
потерпит неудачу. Контравариантность означает, чтоBadFilter
в порядке. Фильтр, который может фильтровать произвольные объекты, может фильтровать и события.MyFilter
фильтрует подклассы, аBadFilter
фильтрует суперклассы. наверняка один из них должен выйти из строя?