0

I have to take arbitrary arguments of lists in a function

This code works fine

a=[1,2,3]
b=[5,6,7]

def joiner(m,n):
    o = []
    return m+n+o

print joiner(a,b)

but when I change the code to arbitrary arguments and it is not working

a=[1,2,3]
b=[5,6,7]

def joiner(*m):
    o = []
    return m+o

print joiner(a,b)

What could be the reason for this

fuesika
  • 3,280
  • 6
  • 26
  • 34

3 Answers3

3

m is a tuple containing the two (or more, or less) lists. You need to loop through m to get a general version of your function

def joiner(*m):
    o = []
    for item in m:
        o += item
    return o

You can do this in a one liner, but I think this is clearer.

John La Rooy
  • 295,403
  • 53
  • 369
  • 502
3

The star * syntax in a function or method signature packs positional arguments into a tuple (see this answer for lots of details). Your second function receives a single argument, called m, that looks (for example) like this:

([1, 2, 3], [5, 6, 7])

If you want to then access each member of that tuple (each argument) individually, you must do that explicitly--Python can't magically intuit that you want to add all your arguments together.

def joiner(*args):
    o = []
    for arg in args: # Iterate over each argument your function received.
        o += arg   # or better, o.extend(arg)
    return o

There are also tools that already exist to do this for you: specifically, itertools.chain:

import itertools
def joiner(*m):
    return list(itertools.chain(*m))

Of course at that point (as others have mentioned), you might as well not write the joiner function at all, since it's just a few extra steps under the hood to wrap an itertools.chain call.

...Actually, any time you do pretty much anything with one or more iterables, you should go look at the itertools module and see if someone has already implemented it for you. :-)

Community
  • 1
  • 1
Henry Keiter
  • 16,863
  • 7
  • 51
  • 80
  • 1
    arg ... so close to a +1 .. get rid of the sum comment ... while true that is junky code, and a bad habit to teach or encourage(less clear and much much much slower than other methods) – Joran Beasley Feb 17 '14 at 23:24
  • 1
    Agreed 100% with Joran. The only reason `sum` works in this case is that the author of the function couldn't think of a good way to make it _not_ work with arbitrary iterables (because `Iterable` didn't exist yet). The right way to write this is with `chain`, as in his answer, or by doing it explicitly. – abarnert Feb 17 '14 at 23:26
  • 1
    The problem with sum here, is that it has quadratic performance for pretty much anything that's not numbers. – John La Rooy Feb 17 '14 at 23:27
  • there now you get my +1 :P – Joran Beasley Feb 17 '14 at 23:28
  • Yes, yes, pardon my impropriety, everybody :-p The `sum` was just a placeholder while I made sure I remembered how `itertools.chain` worked. – Henry Keiter Feb 17 '14 at 23:29
  • 2
    @gnibbler: The real problem with `sum` is that it's misleading. People have proposed "fixes" numerous times to make it use `+=` instead of `+`, which would give it amortized linear or log-linear performance with all mutable iterables (and with strings, for a different reason), but the idea is always rejected because `sum` is for summing numbers, and `chain` is for chaining iterables. – abarnert Feb 17 '14 at 23:29
2

my contribution to the flurry of answers that are all correct :P

import itertools

def joiner(*m):
    return itertools.chain.from_iterable(m)
abarnert
  • 354,177
  • 51
  • 601
  • 671
Joran Beasley
  • 110,522
  • 12
  • 160
  • 179
  • 1
    This is good if you don't actually need a list. But you could just say `joiner = itertools.chain` :) – John La Rooy Feb 17 '14 at 23:26
  • :P I know ... but meh I figured Id keep it in a method like he has it – Joran Beasley Feb 17 '14 at 23:26
  • 2
    @gnibbler: If you actually need a list, `return list(itertools.chain.from_iterable(m))`. – abarnert Feb 17 '14 at 23:27
  • 2
    Or, alternatively, there's [this pattern](http://pastebin.com/Q9vas8bT) to get back a , so joining three `deque`s together returns a `deque`. (Of course joining two `deque`s, a `list`, and a `tuple` also returns a `deque`… but in that case, you're asking for it…) – abarnert Feb 17 '14 at 23:32