3

Say i am using a class from some python package that looks like the following

class foo(object):
    def __init__(self):
        self.a = None
        self.b = None
        self.c = None
        self.d = None
        self.e = None
        self.f = None

Now I need to use attributes b, d, and e of object foobar of class foo in some operation, say call a function qux for instance:

print qux(foobar.b, foobar.d, foobar.e)

Is there any way to create a shorthand version of this, something like the following imagined code:

print qux(*foobar.[b,d,e])

Note the constraints: neither the class nor the function can be changed.

wich
  • 16,709
  • 6
  • 47
  • 72
  • Does decorating `qux` count as "changing" it? You could use the [multimethod](http://www.artima.com/weblogs/viewpost.jsp?thread=101605) decorator and create an alternate version of `qux` that accepts a single `foo` instance. – Kevin Jun 25 '14 at 15:45

2 Answers2

3

Well, getattr and setattr get you close:

Assignment with setattr (not needed for the next to work, just here for illustration):

class foo(object):
    def __init__(self):
        for name in 'abcdef':
            setattr(self, name, None)

Using values with getattr:

print qux(*(getattr(foobar, name) for name in 'bde'))

With normal, longer names you'd need to do in ['foo', 'bar'] instead.

otus
  • 5,572
  • 1
  • 34
  • 48
1

Since you can't modify the class, how about a function that takes an instance and any number of attribute names, and returns a tuple:

class Foo(object):
    def __init__(self):
        self.a = 1
        self.b = 2
        self.c = 3


def getitems(obj, *items):
    values = []

    for item in items:
        values.append(getattr(obj, item))

    return tuple(values)

f = Foo()
print getitems(f, 'a', 'c')  # prints (1, 3)
qux(*getitems(f, 'a', 'c'))

If you are willing to modify the class, you can override __getitem__ to accept a tuple of keys.

class Foo(object):
    def __init__(self):
        self.a = 1
        self.b = 2
        self.c = 3

    def __getitem__(self, item):
        if isinstance(item, basestring):
            # treat single key as list of length one
            item = [item]

        values = []

        for key in item:
            # iterate through all keys in item
            values.append(getattr(self, key))

        return tuple(values)

f = Foo()
print f['a', 'c']  # prints (1, 3)
qux(*f['a', 'c'])
davidism
  • 121,510
  • 29
  • 395
  • 339