1

What is the best way to be able to pass either a list or a value to a function and have it return as

foo(x): foo(x)

foo([x, y, z]): [foo(x), foo(y), foo(z)]?

Is it just testing for whether the input is a list? A try/except block trying to access list elements? Something else?

Jacob Bond
  • 225
  • 2
  • 10
  • You can use `type(x)` to define your logical flow – TayTay Nov 12 '15 at 16:10
  • Or `isinstance(x, list)` – TayTay Nov 12 '15 at 16:11
  • *"A try/except block trying to access list elements?"* - not if you want to take strings, which are also sequences. *"just testing for whether the input is a list?"* - not if you want to do proper duck typing. What are you actually trying to achieve? Could you give a more specific example? It sounds like you want something similar to `map`, which simply requires the second argument to be iterable (e.g. `map(int, 1)` will fail). – jonrsharpe Nov 12 '15 at 16:12

2 Answers2

4

use collections to determine if it is iterable or not. If iterable, do your list logic. If not do your variable logic

import collections

if isinstance(e, collections.Iterable) and not isinstance(e, basestring) :

As pointed out in the comments. Add logic to not include strings

Busturdust
  • 2,447
  • 24
  • 41
2

Here's a simple function foo that takes an element and multiplies it by two. If it's a list, it will return the list of foo-operated elements.

def foo(x):
    if isinstance(x, list): ## Accepts list ONLY
        return [foo(i) for i in x]
    return x * 2

Output:

>>> foo(3)
6
>>> foo([1,2,3])
[2, 4, 6]

Edit:

Per Jon's comment, if you'd like a tuple to be acceptable input, you could do the following:

def foo(x):
    if isinstance(x, (list, tuple)): ## Accepts list OR tuple
        return [foo(i) for i in x]
    return x * 2

This will still return only a list for either a list or tuple input, though. If you want the same type of output as input (i.e. tuple output), then you can amend to the following:

def foo(x):
    if isinstance(x, (list, tuple)): ## Accepts list OR tuple
        result = [foo(i) for i in x]
        return result if not isinstance(x, tuple) else tuple(result)
    return x * 2

New output:

>>> foo(1)
2
>>> foo([1,2,3])
[2, 4, 6]
>>> foo((1,2,3))
(2, 4, 6)

Note also that this will handle odd nested structures:

>>> foo([[1,2,3],[4,5,6],(7,8,9)])
[[2, 4, 6], [8, 10, 12], (14, 16, 18)]
TayTay
  • 6,882
  • 4
  • 44
  • 65
  • And what about `foo((1, 2, 3))`? It doesn't fail, which the user might expect it to as you can't mutate the tuple, but instead returns something weird (`(1, 2, 3, 1, 2, 3)`). – jonrsharpe Nov 12 '15 at 16:14
  • To be fair, he specifically asked for list... but I'll edit... – TayTay Nov 12 '15 at 16:15
  • True, but you should at least comment on the limitations of the approach! – jonrsharpe Nov 12 '15 at 16:16