3

I have a function

def foo(a):
    first_thing = 'first' + a
    second_foo =  'second' + a + 'bar'
    return first_thing, second_foo

which returns tuples. How can I achieve something like

class Thing(object):
    def __init__(self, a):
        first_thing, second_foo = foo(a)
        self.first_thing = first_thing
        self.second_foo = second_foo

in a nicer and more automated fashion?

I experimented with:

def __init__(self, a):
        for key, value in foo(a):
            setattr(self, key, value)

But can't unpack correctly.

2
  • 1
    self.first_thing, self.second_foo = foo(a)? Commented Sep 10, 2017 at 11:19
  • Are you returning an unknown number of arguments? Commented Sep 10, 2017 at 11:19

3 Answers 3

2

Your function returns a tuple of values (a 2-tuple) not an iterable of 2-tuples. You're iterating over that tuple which contains strings, and you can't unpack those returned strings into twos.

You can stick with the original solution or unpack the items directly into the instance attributes:

self.first_thing, self.second_foo = foo(a)

And for many attributes:

_ATTR_NAMES = ('first_thing', 'second_foo')

class Thing(object)
    def __init__(self, a):
        for key, value in zip(_ATTR_NAMES, foo(a)):
            setattr(self, key, value)
Sign up to request clarification or add additional context in comments.

Comments

1

Why not just:

class Thing(object):
    def __init__(self, a):
        self.first_thing, self.second_foo = foo(a)

You do not need the first line inside __init__() function.

As per your comment, you can return a dictionary in your foo function and use setattr(), the updated solution would be:

def foo(a):
    first_thing = 'first' + a
    second_foo =  'second' + a + 'bar'
    return {'first_thing': first_thing, 'second_foo': second_foo}


class Thing(object):
    def __init__(self, a):
        for k, v in foo(a).items():
            setattr(self, k, v)

4 Comments

But this means that I manually need to specify all the values. can't this be made a bit nicer i.e. something like java reflection which would take the literal name i.e. first_thing and store first_thingas an attribute and its respective value?
@GeorgHeiler in this case, you will need to return a dictionary instead of tuple in your foo function
Would you recommend self.__dict__.update(foo(a)) or setattr(self, k, v)?
Personally I recommend setattr() as it's more safer. You can find some details in this answer stackoverflow.com/a/14504828/4575071
1

If your function returns a varying number of arguments, you could return a dictionary from foo instead, and update the __dict__ attribute.

def foo(a):
    return {'first' : 'first' + a, 'second' : 'second' +  a + 'bar'}

class Thing(object):
    def __init__(self, a):
        self.__dict__.update(foo(a))

In [1233]: f = Thing('test')

In [1234]: f.first
Out[1234]: 'firsttest'

In [1235]: f.second
Out[1235]: 'secondtestbar'

Note the caveats with this approach, the most significant one being the lack of control over what is being updated.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.