Я хотел бы определить своего рода универсальный тип «обертки», скажем MyType[T], чтобы он имел тот же интерфейс типа, что и обернутый тип.
from typing import Generic, TypeVar
T = TypeVar("T")
class MyType(Generic):
pass # what to write here?
Итак, например, когда у меня есть тип MyType[int], средство проверки типов должно обрабатывать его так, как если бы это был тип int.
Это возможно? Если да, то как?






Возможно, мне не хватает сути того, что вы ищете. Если да, то я рад пересмотреть этот ответ, но если вы хотите, чтобы новый тип проверялся так же, как и его базовый тип, подумайте:
MyType = int
a: MyType = 1
Запуск b = a + 1 не приводит к ошибкам линтинга, но c = a + "a" должен выдать предупреждение. Что-то вроде: Operator "+" not supported for types "Literal[1]" and "Literal['a']"
Я не уверен, что нужно создавать совершенно новый универсальный класс, если вы хотите, чтобы новый тип вел себя как int (в этом примере).
Это хороший ответ на другой вопрос. :)
Я не хочу представлять это как ответ, просто как предположение (пожалуйста, прокомментируйте, если я вас неправильно понял):
from typing import TypeVar, Generic
T = TypeVar("T")
class MyType(Generic[T]):
def __init__(self, value: T):
self.value = value
# Example usage
x: MyType[int] = MyType(42)
y: MyType[str] = MyType("Hello")
# The type checker will treat x.value as an int and y.value as a str
reveal_type(x.value) # note: Revealed type is "builtins.int"
reveal_type(y.value) # note: Revealed type is "builtins.str"
Для подтверждения вы хотите, чтобы выражение MyType[T] означало для средства проверки статического типа «подкласс MyType и T», так что объявление
class MyType:
attr: object
приведет к следующему (например, используя mypy и int.conjugate в качестве примера):
>>> reveal_type(MyType[int].conjugate) # def (self: builtins.int) -> builtins.int
>>> obj: MyType[int] = MyType[int]()
>>> reveal_type(obj.attr) # builtins.object
Нет, эта идиома не поддерживается при типизации Python. Вместо этого ваш вариант использования должен быть охвачен будущей реализацией типов пересечений с предложенным синтаксисом MyType & T.
Для средства проверки статического типа синтаксис MyType[T] означает и означает только то, что MyType является универсальным типом (включая универсальные структурные типы), а API, который имеет MyType, получен из любых метаклассов, любых базовых классов и чего угодно. заявлено под телом class MyType.
Любая параметризация типа (например, передача int в T в MyType[T]) влияет только на общие типы в базах классов и операторы в теле класса;
В теле класса нет ничего, что могло бы сообщить средству проверки статического типа, что класс наследует API от другого класса, поскольку эта информация уже предоставлена метаклассом и базовым классом(ами);
<type>[T] правильно определен как статически выводимый тип только тогда, когда <type> является определяемым пользователем универсальным типом. Статические типы, выведенные из других произвольных попыток создать допустимое выражение, нестабильны и определяются реализацией, независимо от реализации во время выполнения.
from typing import *
T = TypeVar("T")
class M(type):
def __getitem__(cls, type_: T, /) -> T: ...
class A(metaclass=M): ...
class B:
def __class_getitem__(cls, type_: T, /) -> T: ...
class C(Generic[T]): ...
>>> A_int: TypeAlias = A[int] # mypy: "A" expects no type arguments, but 1 given # pyright: Expected no type arguments for class "A"
>>> B_int: TypeAlias = B[int] # mypy: "B" expects no type arguments, but 1 given # pyright: <no messages>
>>> C_int: TypeAlias = C[int]
>>>
>>> reveal_type(A[int]) # mypy: <overloads of `int.__new__`> pyright: Type of "A[int]" is "Type[int]"
>>> reveal_type(B[int]) # mypy: The type "type[B]" is not generic and not indexable pyright: Type of "B[int]" is "Type[int]"
>>> reveal_type(C[int]) # mypy: Revealed type is "def () -> __main__.C[builtins.int]" pyright: Type of "C[int]" is "Type[C[int]]"