Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python decorator for field

I know there is no such a thing. That's why I'm looking for some nice equivalent. Having this class:

class MyClass:
   a = 5
   b  = "foo"
   c = False

I would like to "group" fields a and b together to be able to somehow iterate over members only from this group. So it would be nice to have some kind of field decorator, like:

class MyClass:
   @bar
   a = 5
   @bar
   b  = "foo"
   c = False

And to have some function like myDir(MyClass, 'bar') that would return ('a', 'b').

What options do we have so far? 1. Name these fields by special convention like 'a_bar', 'b_bar' - but I can't do it unfortunately. 2. make a list of names as another class member - I would like to keep this grouping attribute close to attribute so I don't like this approach. 3. Instead of assigning 5 to 'a' and "foo" to be I can make classes that inherit from integer and string and add another base class like 'Group' and then check the types - this way I will have to generate this class each time I have new type, so I don't like this solution either.

Any other ideas?

like image 758
mnowotka Avatar asked Nov 23 '12 16:11

mnowotka


1 Answers

Decorators are just syntactic sugar for a function call, so to apply a decorator to an attribute you just need to call it on the initialiser:

a = bar(5)

In your case you can create objects that implement the descriptor protocol:

class GroupedAttribute(object):
    def __init__(self, group, obj):
        self.group = group
        self.obj = obj
    def __get__(self, obj, owner):
        return self.obj
    def __set__(self, obj, value):
        self.obj = value

For elegance, you could write a class for attribute groups:

class GroupedAttribute(object):
    def __init__(self, group, obj):
        self.group = group
        self.obj = obj
    def __get__(self, obj, owner):
        return self.obj
    def __set__(self, obj, value):
        self.obj = value

class AttributeGroup(object):
    def __call__(self, obj):
        return GroupedAttribute(self, obj)
    def __get__(self, obj, owner):
        return BoundAttributeGroup(self, obj, owner)

class BoundAttributeGroup(object):
    def __init__(self, group, obj, owner):
        self.group = group
        self.obj = obj
        self.owner = owner
    def __dir__(self):
        items = dir(self.owner if self.obj is None else self.obj)
        return [item for item in items if
                getattr(self.owner.__dict__.get(item, None),
                        'group', None) is self.group]

Usage:

class MyClass(object):
    bar = AttributeGroup()
    a = bar(5)
    b = bar("foo")
    c = False
dir(MyClass.bar)    # ['a', 'b']
like image 182
ecatmur Avatar answered Oct 10 '22 21:10

ecatmur