Я пытаюсь создать базовый класс, который работает для любого CRUD в приложениях, и я видел следующую реализацию:
ModelType = TypeVar("ModelType", bound=Base)
CreateSchemaType = TypeVar("CreateSchemaType", bound=BaseModel)
UpdateSchemaType = TypeVar("UpdateSchemaType", bound=BaseModel)
class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]):
def __init__(self, model: Type[ModelType]):
"""CRUD object with default methods to Create, Read, Update,
Delete (CRUD).
**Parameters**
* `model`: A SQLAlchemy model class
* `schema`: A Pydantic model (schema) class
"""
self.model = model
'...crud methods'`
Generic — это способ определить абстрактный класс, содержащий указанные объекты (в данном случае [ModelType, CreateSchemaType, UpdateSchemaType]), или для чего используется generic?
Большое спасибо за ваши наблюдения. В частности, я хотел бы знать в этом случае, что такое использование общего? Это для указания типа переменных, которые должен иметь класс?






Если ваш вопрос касается цели набора текста. Общий , я бы посоветовал вам прочитать PEP 484 . В нем есть раздел, посвященный определяемым пользователем универсальным классам с некоторыми примерами специально для этого, но ИМХО стоит прочитать весь документ. Если вы не уверены во всей концепции универсальных типов, статьи Википедии о параметрическом полиморфизме и универсальном программировании, возможно, даже стоит просмотреть.
Проще говоря, вы можете использовать базовый класс Generic для определения своих собственных классов в общем виде, то есть параметризованных в отношении одного или нескольких аргументов типа. Эти параметры типа создаются с помощью typing.TypeVar. Стоит отметить, что в большинстве случаев эти вещи важны только для целей безопасности типов, которая на самом деле не обеспечивается самим Python. Вместо этого с этими вещами работают статические средства проверки типов (в большинстве IDE они встроены).
Что касается вашего примера, вполне возможно определить ваш класс в общем виде и, таким образом, улучшить свой собственный опыт кодирования, потому что вы, вероятно, получите полезные автоматические предложения и предупреждения от вашей IDE. Это действительно становится полезным, только если вы используете переменные типа где-то еще в своем классе. Пример:
from typing import Generic, TypeVar
class Base:
pass
ModelType = TypeVar("ModelType", bound=Base)
class CRUDBase(Generic[ModelType]):
def __init__(self, model: type[ModelType]):
self.model = model
def get_model_instance(self) -> ModelType:
return self.model()
class Sub(Base):
def foo(self) -> None:
print("hi mom")
if __name__ == "__main__":
crud_a = CRUDBase(Sub)
crud_b = CRUDBase(Base)
a = crud_a.get_model_instance()
b = crud_b.get_model_instance()
a.foo()
b.foo() # error
Хорошая проверка типов, такая как mypy, будет знать, что a относится к типу Sub и, следовательно, имеет метод foo, тогда как b относится к типу Base и, следовательно, не имеет. И это будет известно только по тому, как мы аннотировали CRUDBase.
PyCharm, например, борется с этим (не знаю почему). К счастью, мы можем помочь с явными аннотациями типов, потому что мы определили CRUDBase как общий тип:
...
crud_a: CRUDBase[Sub] = CRUDBase(Sub)
crud_b: CRUDBase[Base] = CRUDBase(Base)
a = crud_a.get_model_instance()
b = crud_b.get_model_instance()
a.foo()
b.foo() # PyCharm marks `foo` and complains
Обратите внимание, что пока в нашем CRUDBase нет ничего особенно «абстрактного». Он полностью автономен и работает так (хотя пока и не очень полезно).
Если вы хотите, чтобы класс был абстрактной базой и не создавался напрямую, модуль abc предоставит вам необходимые инструменты. Вы можете определить абстрактный базовый класс и абстрактные методы, которые должны быть реализованы во всех подклассах. Но я думаю, теперь ясно, что это другая концепция. Идея состоит в том, что абстрактный класс не предназначен для создания экземпляров, только его подклассы.
Я надеюсь, что это поможет указать вам несколько полезных направлений.
Большое спасибо! Это гораздо более полный ответ, чем я мог себе представить. Такие люди, как вы, делают это сообщество мощным инструментом для всех!
Не уверен, что ваш настоящий вопрос здесь. Общий не обязательно должен быть абстрактным. Также абстрактный класс не обязательно должен быть универсальным. Эти два понятия иногда пересекаются, но они различны. Пожалуйста, будьте более конкретными. Что именно вам не понятно? И задавайте только один вопрос за раз. Также «есть ли лучший способ» крайне расплывчато. Ответ, безусловно, да, независимо от контекста.