TheRogueWolf
TheRogueWolf

Reputation: 353

Accessing attributes of class instances passed as optional arguments

I have two class instances which have list attributes, e.g.:

foo.range = [1,2]
bar.range = [3,4]

I also have a function which takes multiple arguments:

def permutations(*args):
    return list(itertools.product(arg.range for arg in args))

I want permutations(foo, bar) to return all permutations of those two (or more) lists (i.e. [(1,3), (1,4) …]) but I actually get [([1, 2],), ([3, 4],)]

Could someone please help me to understand where am I going wrong and how to achieve the result I'm hoping for?

Upvotes: 0

Views: 82

Answers (1)

Ashwini Chaudhary
Ashwini Chaudhary

Reputation: 251196

itertools.product expects the iterables as individual arguments(itertools.product(*iterables[, repeat])), so you need to unpack the items to it using the the splat(*) operator:

>>> def permutations(*args):
        return list(itertools.product(*(arg.range for arg in args)))

>>> permutations(foo, bar)
[(1, 3), (1, 4), (2, 3), (2, 4)]

Consider this simple function, it will collect all positional arguments passed to it in args:

>>> def func(*args):
    print args
    print list(args[0])
...

When we pass it a generator expression it is collected as one individual item in the args tuple:

>>> func(x for x in range(5))
(<generator object <genexpr> at 0x7fda2ab4e780>,)
[0, 1, 2, 3, 4]

To fix this we need to unpack our generator expression, also as somethine like *x for x in range(5) is not a valid syntax in Python, we need to add extra parenthesis around the generator expression:

>>> func(*(x for x in range(5)))
(0, 1, 2, 3, 4)
# Failed as expected for args[0]
Traceback (most recent call last):
  File "<ipython-input-215-13af4340dad1>", line 1, in <module>
    func(*(x for x in range(5)))
  File "<ipython-input-213-08941e2a3c06>", line 3, in func
    print list(args[0])
TypeError: 'int' object is not iterable

Upvotes: 2

Related Questions