1

I want to write a function that takes either an int or a list of int as parameter and processes that values.

something like that:

def func(input):
  if isinstance(input, int):
    print(input)
  else:
    for i in input:
      print(i)

this doesn't look very pythonic to me, but I don't know how to do it better. Is there a way to "loop" over the int or "pack" the int into a list that handles both options

Thanks

  • 2
    You could use something like `lst = [input] if isinstance(input, int) else input` and then iterate over `lst` in your loop... – Ed Ward Feb 21 '20 at 11:19
  • It's reasonably "pythonic". A way I do this more often is something like `if not isinstance(x, list): x = [x]`, thus making it into a one element list. Then you can proceed assuming the input was a list to begin with. Your list-handling code should of course be able to consume a list of any size in principle. – Iguananaut Feb 21 '20 at 11:21
  • Thanks, this are two beautiful one-liners and I can handle the following all the same. – freitagvormittag Feb 21 '20 at 12:09

5 Answers5

3

You can also follow the pythonic principle EAFP (Easier to ask for forgiveness than permission)

def func(your_input):
    try:
        for i in your_input:
            print(i)
    except TypeError:
        print(your_input)

You try to iterate for entries in input and print them. If type of input is not iterable (like an int), then trying to iterate over a non-iterable object raises a TypeError exception. In the except clause you can then print the input.

EDIT: As @buran noted, input is a reserved keyword for Python, so you should avoid it.

jcf
  • 602
  • 1
  • 6
  • 26
  • 1
    Please, replace `input` with some other name. Although used by OP, it's a built-in function and should not be overridden. – buran Feb 21 '20 at 11:38
  • Ups, I ovelooked that, fixed! – jcf Feb 21 '20 at 11:45
  • EAFP is an interesting principle and I am trying to use it more and more. But the background of my question was that I don't want to write the print-Statement double. – freitagvormittag Feb 21 '20 at 12:06
2

I wouldn't worry so much about it being Pythonic or not. But here is another way you could do it that doesn't restrict you to lists or ints, but rather checks if you have an iterable or not:

def func(input):
    if not hasattr(input, '__iter__'):
        input = [input]

    for i in input:
        print(i)

But another potentially cleaner option to consider could be this:

def func(*inputs):
    for i in inputs:
        print(i)

You would call this function slightly differently: func(5) for scalars and func(*lst) for iterables.

Seb
  • 4,422
  • 14
  • 23
  • 1
    I like your first method. Regarding the second one, it is a little problematic because it would be like saying that he can just do the loop for printing in the function and call it as `func([5])` for ints. I think the idea of the question is to make it transperrant for the caller of the function... – Tomerikoo Feb 21 '20 at 11:29
  • 1
    Very good point. However I wanted to include it, because to me the need for transparently handling scalars and iterables as the same parameter can (sometimes) indicate a problem with the design and in those cases it may be better to make it obvious to the caller what is expected to pass. – Seb Feb 21 '20 at 11:35
2

For sake of completeness, in addition to @jcf answer, you can use functoools.sigledispatch (or functools.singledispatchmethod if in class) it allows to overload function with different implementation, depending on type of first argument

from functools import singledispatch

@singledispatch
def func(foo):
    print(foo)

@func.register(list)
def _(foo):
    for item in foo:
        print(item)

func(1)
func([2, 3, 4])

Now, the question is what you do if you get something different from list, like tuple, or generator, etc. You may want to use abstract classes from collections.abc instead of list

On a side note - don't use input as name - it's a built-in function.

buran
  • 13,682
  • 10
  • 36
  • 61
0
def func(input):
    for i in ([input] if isinstance(input, int) else input):
        print(i)

"packs" an int into a list as you wanted, but I don't think it is any more elegant than your original code.

Błotosmętek
  • 12,717
  • 19
  • 29
-2
if type(input) == int:
    print('Integer')
    # Do integer operation
elif isinstance(input, list):
    print('List')
    # Do list operation