LINUX.ORG.RU

установить тип объекта

 ,


0

1

Как оказалось оператор isinstance считает различными типы объектов в зависимости от пути к ним. Т.е. разные по типам объекты

<class '__main__.MyClass22'>

и

<class 'module2.module22.MyClass22'>

Как правильно установить тип объекта? У меня есть функция, которая в зависимости от типа объекта реализует различные алгоритмы ...

P.S. помогло object.__class__.__name__ , но как-то без магических методов не по-питонски это

У меня есть функция, которая в зависимости от типа объекта реализует различные алгоритмы

Вот так и есть неправильно. Правильно будет сделать родительский класс с абстрактным методом. В потомках реализовать этот метод и в твоей функции его использовать. Делать различное поведение по isinstance или type допустимо только для встроенных типов или типов из внешних либ

Aswed ★★★★★ ()
Ответ на: комментарий от Aswed

Согласен и понимаю это. Но, проблема с синтаксисом или архитектурой. Как сделать не знаю.

Есть Data Transfer Objects у меня, например, А и В:

@dataclass
class Base:
    pass

@dataclass
class A(Base):
    x: int

@dataclass
class B(Base):
    y: str

и мне нужно их записывать в базы данных

def save_to_db(c):
    if c.__class__.__name__ == 'A':
         # save A.x
    if c.__class__.__name__ == 'B':
         # save B.y
Причем функции save_to_db лежат в разных отдельных модулях, заточенные под свою СУБД. И эти модули будут дополняться и меняться - т.е. в не самый лучший вариат в приведенной выше иерархии класса предусматривать работы со всевозможными БД, к-е есть и будут.

P.S. похоже придется save_a_to_db, save_b_to_db ...

scientistpython ()
Последнее исправление: scientistpython (всего исправлений: 1)
Ответ на: комментарий от scientistpython

Во первых да, несколько СУБД в одном проекте это очень плохо. Во-вторых как вообще приведенный тобой код может не дружить с isinstance? Ты же туда явно передаешь класс A импортированный из конкретного модуля

Aswed ★★★★★ ()

Если же ты намеренно сделал два разных класса A, в разных модулях, которые имеют одинаковые поля, что бы в них была сериализация, то это вообще беда. Не делай так. Просто унаследуй один от другого. Или, если у них разное поведение, сделай базовый класс BaseA, куда сложишь общие поля. Оба отнаследуй от BaseA, а на месте проверяй isinstance(x, BaseA)

Aswed ★★★★★ ()
Ответ на: комментарий от scientistpython

Это какая-то муть, что в оппосте, что в этом. Сериализаторы/сохраняторы надо делать ближе к самим датаклассам, а разные типы бд абстрагировать через аргумент к этим сохраняторам. Это даже без учета питоноидеалов, просто здравый смысл, чтобы не поддерживать десятки условий и не размазывать код по сорцам. Судя по доке на датакласс, ничего не мешает впилить в каждый из них def save(db_interface): …, или даже один раз в их базовый, если пользуешься интроспекцией или asdict. Ты бы лучше общую картину описал, что хочешь сделать, потому что очень чувствуется фиговая архитектура.

А исинстанс не работает потому что у тебя не пути к классам разные, а сами классы, просто у них название совпало, и ожидать этого ощемта не надо было.

anonymous ()
Ответ на: комментарий от Aswed

Класс один и тот же. Классов с одним и тем же названием в разных модулях нет. Вот исскуственный пример, в котором при запуске модуля m2 isinstance отрабатывает правильно. При запуске m1 - нет.

m1

from dataclasses import dataclass

@dataclass
class A:
    x: int

@dataclass
class B:
    y: str

if __name__ == '__main__':
    from m2 import data_save
    a = A(x=1)
    data_save(a)

m2

from m1 import A, B


def data_save(obj) -> None:
    if isinstance(obj, A):
        print('save A')
    if isinstance(obj, B):
        print('save B')

if __name__ == '__main__':

    a = A(x=1)
    data_save(a)
    b = B(y='v')
    data_save(b)

P.S. Что касается архитектуры с разными БД - она дана в поставновке задачи изначально и я это не изменю.

scientistpython ()
Ответ на: комментарий от eternal_sorrow

я тоже не видел, пока не нарвался )))

m1

from dataclasses import dataclass

@dataclass
class A:
    x: int

@dataclass
class B:
    y: str

if __name__ == '__main__':
    from m2 import data_save
    a = A(x=1)
    data_save(a)

m2

from m1 import A, B


def data_save(obj) -> None:
    if isinstance(obj, A):
        print('save A')
    elif isinstance(obj, B):
        print('save B')
    else:
        print('тип не опознан')

запускаем m1

тип не опознан

P.S. вариант починки этого учебного примера

if __name__ == '__main__':
    from m1 import A, B
    from m2 import data_save
    a = A(x=1)
    data_save(a)

а в проекте в целом строго из одной точки подключать все модули, что тоже может быть не простой задачей

cvprog ()
Последнее исправление: cvprog (всего исправлений: 2)
Ответ на: комментарий от cvprog

Лол, так у тебя не в типах проблема, а в циклических зависимостях. Нельзя делать в m1 import m2, а потом сразу же в m2 делать import m1. Сделай в m2 что-то типа такого:

@lru_cache(maxsize=1)
def required_classes() -> Dict[type, Callable]:
    from m1 import A, B
    from ... import ... # прочие импорты
    return {A: method2, B: method1, ...}

def data_save(obj: Any) -> None:
    methods = required_classes()
    for cls, method in methods.items():
        if isinstance(obj, cls):
            return method(obj)
Aswed ★★★★★ ()
Последнее исправление: Aswed (всего исправлений: 1)