Каков наилучший способ найти наиболее подходящий тип для существующего? - PullRequest
0 голосов
/ 07 марта 2009

У меня есть реестр классов и типов в Python 2.5, например:

class ClassA(object):
    pass

class ClassB(ClassA):
    pass 

MY_TYPES = {
    basestring : 'A string',
    int : 'An integer',
    ClassA : 'This is ClassA or a subclass',
}

Я бы хотел иметь возможность передавать типы в функцию и искать в ней ближайший соответствующий тип в иерархии. Итак, поиск str вернул бы "A string" и поиск ClassB вернул бы "This is ClassA or a subclass" Проблема в том, что я не знаю, как найти суперкласс (или, скорее, проследить цепочку MRO) типа объект.

Какой лучший способ справиться с этим?

Ответы [ 4 ]

4 голосов
/ 07 марта 2009
from inspect import getmro
[st for cls, st in MY_TYPES.items() if cls in getmro(ClassB)]

['This is ClassA or a subclass']

или если вас интересует только версия генератора первого совпадения:

(st for cls, st in MY_TYPES.iteritems() if cls in getmro(ClassB))
2 голосов
/ 07 марта 2009

Чтобы получить суперклассы класса, используйте __bases__:

class ClassA(object):
    pass

class ClassB(ClassA):
    pass

print ClassB.__bases__
(<class '__main__.ClassA'>,)

Остерегайтесь таких вещей, как int. База для всех этих будет <type 'object'>. Вы должны будете провести некоторое тестирование и итерацию, чтобы соответствовать ключам dict, которые вы указали в своем примере.

Другой вариант - использовать isinstance для любого экземпляра объекта или issubclass для параметров, проверяя каждый на соответствие вашим ключам. Некоторые считают isinstance и его подобие знаком дьявола, но c'est la vie. Опять же, остерегайтесь использования issubclass с целыми числами и других подобных типов. Вам, вероятно, нужно будет объединить несколько подходов с учетом ваших ключей.

1 голос
/ 07 марта 2009

(st для cls, st в MY_TYPES.iteritems (), если cls в getmro (ClassB))

Более простой способ написать это будет:

(st for cls, st in MY_TYPES.iteritems() if issubclass(ClassB, cls))

Однако это не находит «ближайшего» совпадения; если бы «объект» был в поиске, он мог бы соответствовать всему! Если в поиске были вещи, которые были подклассами других вещей, или вы хотели поддерживать множественное наследование, вам нужно было бы выбрать тот, который был первым в MRO:

for cls in inspect.getmro(ClassB):
    if cls in MY_TYPES:
        print MY_TYPES[cls]
        break
else:
    print 'Dunno what it is'

Во всяком случае ... Я бы вообще рассматривал поиск типов как небольшой запах кода, разве нет лучшего способа сделать то, что вы хотите?

0 голосов
/ 07 марта 2009

Это действительно работа для общих функций. См. PEAK-Rules и PEP 3124 . Универсальные функции позволят вам отправлять произвольные функции на основе типов аргументов или даже более сложных выражений.

Или, если вы действительно любите наказания, посмотрите на эту главу из Практического Общего Лиспа .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...