Создание прокси-объекта/псевдонима для класса
Моя задача состоит в следующем: IDE должна автоматически определять доступные методы класса, переданного в качестве аргумента в конструктор, а данный конструктор должен как бы обретать те же методы, что и переданный в него класс. Поведение, которого я хочу добиться, крайне схоже с прокси-объектом или псевдонимами (alias
) в sqlalchemy
. Однако попытки определить, как оно там устроено внутри, не увенчались успехом. Простой пример того, как я хочу видеть эту реализацию:
from typing import Type, Any
class BaseSymbol:
def __init__(self, value=None):
self.value = value
def get_value(self):
return self.value
class A(BaseSymbol):
def __init__(self):
super().__init__("a")
def get_a(self):
return super().get_value()
class Alphabet:
def __init__(self, symbol_type: Type[BaseSymbol] = A):
self.symbol = symbol_type()
def __setattr__(self, key: str, value: Any):
"""Позволяет устанавливать атрибуты self.symbol как у Alphabet"""
if key == "symbol":
return super().__setattr__(key, value)
if hasattr(self.session, key):
return self.session.__setattr__(key, value)
return super().__setattr__(key, value)
def __getattr__(self, item: str):
"""Позволяет обращаться к self.symbol как к экземпляру Alphabet"""
return self.session.__getattribute__(item)
test_instance = Alphabet(A)
# После этого IDE должна предоставлять подсказки о методах класса A, например:
# test_instance. должно отобразить get_a() и value
# при этом если будет создан новый класс например "B" и в нём будет новый метод он тоже должен отобразиться
Пробовал через TypeVar и Generic, но тоже не помогло.
Изменено:
Небольшой пример из sqlalchemy
с использованием alias
-а:
from sqlalchemy import MetaData, create_engine
from sqlalchemy.orm import as_declarative, Mapped, mapped_column, aliased
@as_declarative()
class Base:
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True, nullable=False)
metadata = MetaData()
class Person(Base):
__tablename__ = 'person'
name: Mapped[str]
age: Mapped[str]
engine = create_engine("sqlite:///container.db")
Base.metadata.create_all(bind=engine)
p = aliased(Person)
print(p.name) # >>> aliased(Person).name