Как создать различный тип для переменной класса и переменной экземпляраPython

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Как создать различный тип для переменной класса и переменной экземпляра

Сообщение Anonymous »

Я хочу объяснить Pyright, что мои переменные в классе и экземпляре имеют разные типы.
Мне удалось перегрузить __get __ метод для достижения этого, но теперь Pyright жалуется на инициализацию экземпляров.

Код: Выделить всё

module.py

Код: Выделить всё

import dataclasses
import typing as ty

class CmpOperator:
sign: str

def __init__(self, field_name: str, value: ty.Any):
self.field_name = field_name
self.value = value

class GtCmpOperator(CmpOperator):
sign = ">"

class Field[T]:
def __init__(
self,
model_name: str,
name: str,
default_value: T,
python_type: ty.Type[T],
):
self.default_value = default_value
self.model_name = model_name
self.name = name
self.python_type = python_type

def __gt__(self, other: T) -> GtCmpOperator:
return GtCmpOperator(f"{self.model_name}.{self.name}", other)

def init_model(model: ty.Type[ty.Any]) -> None:
if not dataclasses.is_dataclass(model):
raise TypeError(f"Model `{model.__name__}` is not a dataclass")
for field_name, field_type in ty.get_type_hints(model).items():
field = Field(
model.__name__,
field_name,
getattr(model, field_name, None),
field_type,
)
setattr(model, field_name, field)

def some_work[T](model: ty.Type[T], cmp: CmpOperator) -> T:
assert isinstance(cmp, CmpOperator)

< /code>
module.pyi

Код: Выделить всё

import typing as ty

class CmpOperator:
sign: str
def __init__(self, field_name: str, value: ty.Any):
self.field_name: str
self.value: ty.Any

class GtCmpOperator(CmpOperator): ...

class Field[T]:
def __init__(
self,
model_name: str,
name: str,
default_value: T,
python_type: ty.Type[T],
):
self.default_value: T
self.model_name: str
self.name: str
self.python_type: ty.Type[T]
@ty.overload
def __get__(self, obj: None, owner: type) -> ty.Self: ...
@ty.overload
def __get__(self, obj: object, owner: type) -> T: ...
@ty.overload
def __set__(self, obj: None, value: Field) -> None: ...
@ty.overload
def __set__(self, obj: object, value: T) -> None: ...
def __gt__(self, other: T) -> GtCmpOperator: ...

def init_model(model: ty.Type[ty.Any]) -> None: ...
def some_work[T](model: ty.Type[T], cmp: CmpOperator) -> T: ...

< /code>
main.py

import typing as ty
from dataclasses import dataclass

from module import Field, init_model, some_work

@dataclass
class Model1:
field: int = 0

@dataclass
class Model2:
# Literal[0] is not assignable to Field[int]
field: Field[int] = 0

if __name__ == "__main__":
init_model(Model1)
assert isinstance(Model1.field, Field)
assert isinstance(Model1().field, int)
# "bool" is not assignable to "CmpOperator"
obj = some_work(Model1, Model1.field > 0)
# It`s fine
obj = Model1(field=1)

init_model(Model2)
assert isinstance(Model2.field, Field)
assert isinstance(Model2().field, int)
# It`s fine
obj = some_work(Model2, Model2.field > 0)
# Literal[1] is not assignable to Field[int]
obj = Model2(field=1)

< /code>
Asserts are true, but Pyright complains about something in both cases.

Подробнее здесь: https://stackoverflow.com/questions/796 ... e-variable
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»