2009-08-11 3 views
0

У меня есть код на Python, где у меня будет куча классов, каждый из которых будет иметь атрибут _internal_attribute. Я хотел бы иметь возможность генерировать отображение этих атрибутов в исходный класс. По сути, я хотел бы быть в состоянии сделать это:Атрибуты обратного сопоставления классов для классов в Python

class A(object): 
    _internal_attribute = 'A attribute' 
class B(object): 
    _internal_attribute = 'B attribute' 

a_instance = magic_reverse_mapping['A attribute']() 
b_instance = magic_reverse_mapping['B attribute']() 

Что я здесь отсутствует, как генерировать magic_reverse_mapping Dict. У меня есть ощущение, что наличие метакласса A и B - правильный способ сделать это; это кажется правильным?

ответ

5

Вы можете использовать мета-класс для автоматической регистрации классы в magic_reverse_mapping:

magic_reverse_mapping = {} 

class MagicRegister(type): 
    def __new__(meta, name, bases, dict): 
     cls = type.__new__(meta, name, bases, dict) 
     magic_reverse_mapping[dict['_internal_attribute']] = cls 
     return cls 

class A(object): 
    __metaclass__ = MagicRegister 
    _internal_attribute = 'A attribute' 

afoo = magic_reverse_mapping['A attribute']() 

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

magic_reverse_mapping = {} 

def magic_register(cls): 
    magic_reverse_mapping[cls._internal_attribute] = cls 
    return cls 

@magic_register 
class A(object): 
    _internal_attribute = 'A attribute' 

afoo = magic_reverse_mapping['A attribute']() 

Или вы могли бы сделать это вручную. Это не то, что гораздо больше работы без использования магии:

reverse_mapping = {} 

class A(object): 
    _internal_attribute = 'A attribute' 

reverse_mapping[A._internal_attribute] = A 

Глядя на различные варианты, я думаю, версия декоратор будет самым приятным в использовании.

+0

Обратите внимание, что для декоратора класса требуется Python> = 2.6. – nikow

+0

Решение декоратора кажется идеальным, по какой-то причине я думал, что декораторы класса были только Py3k. Я обвиняю PEP-3129 в том, что они включены в 3k и не упоминают, что они также находятся в версии 2.6. – wxs

3

Вам нужна структура данных, чтобы сохранить список применимых классов в первую очередь, но вам не нужно его генерировать в первую очередь. Вместо этого вы можете читать классы из глобальных переменных. Это, естественно, предполагает, что ваши классы расширяются object, как и в первом посте.

def magic_reverse_mapping(attribute_name, attribute_value): 
    classobjects = [val for val in globals().values() if isinstance(val, object)] 
    attrobjects = [cls for cls in classobjects if hasattr(cls, attribute_name)] 
    resultobjects = [cls for cls in attrobjects if object.__getattribute__(cls, attribute_name) == attribute_value] 
    return resultobjects 

magic_reverse_mapping('_internal_attribute', 'A attribute') 
#output: [<class '__main__.A'>] 

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

magic_reverse_mapping('_internal_attribute', 'A attribute')[0]() 
#output: <__main__.A object at 0xb7ce486c> 

В отличие от ответа STH, вы не должны добавить декоратор к классам (изящное решение, хотя). Однако невозможно исключить любые классы, которые находятся в глобальном пространстве имен.

+0

«Список классов» - это именно то, чего я хочу избежать, это означает, что в любое время, когда я добавляю новый подкласс, я должен помнить, чтобы добавить его в два места. – wxs

+0

Хм, мне нравится это лучше теперь после редактирования ... Я действительно думаю, что пойду с помощью декоратора. Это более явное и менее волшебное. – wxs

+0

@wxs: Спасибо. То, как вы это сформулировали, звучит правильно ... Решение sth более Pythonic. –

Смежные вопросы