4

I have the following function. Ideally, I want to have either a single string or a list of strings passed as an input. In either case, I need to use .upper on it. But, when only a single string is passed, the iterator iterates through each character. How can I have an if statement that tests whether a list of strings or a single string? (I can't seem to avoid the iterable nature of strings)

def runthis(stringinput):

    for t in stringinput:
        t = t.upper()
Braiam
  • 1
  • 11
  • 47
  • 78
keynesiancross
  • 3,441
  • 15
  • 47
  • 87
  • So, even if `stringinput` was a list of strings, your code wouldn't modify it. – juanpa.arrivillaga Jan 17 '17 at 17:27
  • 2
    Seems nicer to always accept a list of strings, which may contain only a single string. What is the value in letting the caller pass you an un-listed string? – amalloy Jan 17 '17 at 17:29

4 Answers4

4

Check the type using isinstance.

def runthis(stringinput):
    if isinstance(stringinput, list):
        for t in stringinput:
            t = t.upper()
            # Some other code should probably be here.
    elif isinstance(stringinput, basestring):
        t = t.upper()
        # Some other code perhaps as well.
    else:
        raise Exception("Unknown type.")

Use str instead of basestring for Python 3.

Rok Povsic
  • 4,626
  • 5
  • 37
  • 53
1

You can use isinstance() to check whether your function arg is of type list or not:

def to_upper(arg):
    if isinstance(arg, list):
        return [item.upper() for item in arg]  # This is called list comprehension
    else:
        return arg.upper()
ettanany
  • 19,038
  • 9
  • 47
  • 63
1

One way would be to explicitly check if the argument is a list or a string and handle it differently within conditional clauses.

An alternative that I think might be nicer (if it's suitable for your use case) might be the following:

def runthis(*stringinput):
    for t in stringinput:
        t = t.upper()
        print(t)
    print()

runthis("test") # TEST
runthis("another", "test")  # ANOTHER TEST
runthis(*["one", "final", "test"]) # ONE FINAL TEST

However, this approach isn't appropriate if calling code may provide lists without splatting it.


This approach relies on the usage of the * operator, which here is used in two different ways.

In the function definition context (*stringinput), this operator essentially makes stringinput a variadic argument; that is, an argument that "scoops up" all arguments passed to the function into a tuple, which for the purposes of runthis acts like a list (it can be iterated over). If I were to make a call runthis("foo", "bar", "baz"), stringinput would have the value ("foo", "bar", "baz").

You can read more about variadic arguments here.

In the function invocation context (runthis(*["one", "final", "test"])), this operator will "splat" or unpack each element of the list. Essentially, runthis(*["one", "final", "test"]) is equivalent to runthis("one", "final", "test").

You can read more about splatting here.

Tagc
  • 8,736
  • 7
  • 61
  • 114
0

You could use the type() function as so:

if type(stringinput) is list:
    #Your list code
elif type(stringinput) is str:
    #Your string code
else:
    #stringinput isn't a list or a string, throw an error
Joseph
  • 193
  • 11