Класс декоратора Python для преобразования методов в элементы словаря

Интересно, есть ли разумный простой способ заставить этот код (с небольшими изменениями) работать.

class Info(object):
    @attr("Version")
    def version(self):
        return 3

info = Info()
assert info.version == 3
assert info["Version"] == 3

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

Дополнительная информация:

Причина, по которой я хочу предоставить два интерфейса для доступа к одной и той же информации, заключается в следующем.

Я хотел бы иметь класс, похожий на диктофон, который использует ленивые ключи. Например. info["Version"] должен вызывать и кэшировать другой метод и прозрачно возвращать результат. Я не думаю, что это работает только с диктовками, поэтому мне нужно создать новые методы. Методы сами по себе тоже не помогут, потому что есть некоторые атрибуты, которые легче определить с помощью чистого синтаксиса словаря.

В любом случае, это, наверное, не лучшая идея…


person Debilski    schedule 20.07.2010    source источник
comment
См. этот вопрос, который может быть полезен: stackoverflow. ком/вопросы/3054372/   -  person adamk    schedule 20.07.2010
comment
Является ли ключ dict (версия) всегда заглавной версией имени атрибута (version)?   -  person unutbu    schedule 20.07.2010
comment
Нет, это также может быть информация о версии, довольно произвольная.   -  person Debilski    schedule 20.07.2010


Ответы (2)


Если имя атрибута (version) всегда является строчной версией ключа словаря ("Version"), вы можете настроить его следующим образом:

class Info(object):
    @property
    def version(self):
        return 3
    def __getitem__(self,key):
        if hasattr(self,key.lower()):
            return getattr(self,key.lower())

Если вы хотите, чтобы ключ dict был произвольным, то это все еще возможно, хотя и сложнее:

def attrcls(cls):
    cls._attrdict={}
    for methodname in cls.__dict__:
        method=cls.__dict__[methodname]
        if hasattr(method,'_attr'):
            cls._attrdict[getattr(method,'_attr')]=methodname
    return cls

def attr(key):
    def wrapper(func):
        class Property(object):
            def __get__(self,inst,instcls):
                return func(inst)
            def __init__(self):
                self._attr=key
        return Property()
    return wrapper

@attrcls
class Info(object):
    @attr("Version")
    def version(self):
        return 3
    def __getitem__(self,key):
        if key in self._attrdict:
            return getattr(self,self._attrdict[key])

Я предполагаю, что главный вопрос в том, хороший ли это интерфейс? Зачем предоставлять два синтаксиса (с двумя разными именами) для одного и того же?

person unutbu    schedule 20.07.2010
comment
Вы правы насчет двух синтаксисов. Я добавил еще немного информации. - person Debilski; 20.07.2010

Не банально. Вы можете использовать метакласс для обнаружения декорированных методов и соответствующим образом обернуть __*attr__() и __*item__().

person Ignacio Vazquez-Abrams    schedule 20.07.2010