views:

59

answers:

2

I wonder if there is a reasonable easy way to allow for this code (with minor modifications) to work.

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

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

Ideally, the code would do some caching/memoising as well, e.g. employ lazy attributes, but I hope to figure that out myself.

Additional information:

The reason why I want provide two interfaces for accessing the same information is as follows.

I’d like to have a dict-like class which uses lazy keys. E.g. info["Version"] should call and cache another method and transparently return the result. I don’t think that works with dicts alone, therefore I need to create new methods. Methods alone won’t do either, because there are some attributes which are easier to define with pure dictionary syntax.

It probably is not the best idea anyway…

A: 

Not trivially. You could use a metaclass to detect decorated methods and wrap __*attr__() and __*item__() appropriately.

Ignacio Vazquez-Abrams
+1  A: 

If the attribute name (version) is always a lowercase version of the dict key ("Version"), then you could set it up this way:

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

If you wish the dict key to be arbitrary, then its still possible, though more complicated:

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])

I guess the larger question is, Is it a good interface? Why provide two syntaxes (with two different names) for the same thing?

unutbu
You’re right about the two syntaxes. I added some more information.
Debilski