How can I tell if a python variable is a string or a list?

I have a routine that takes a list of strings as a parameter, but I'd like to support passing in a single string and converting it to a list of one string. For example:

def func( files ):
    for f in files:
        doSomethingWithFile( f )

func( ['file1','file2','file3'] )

func( 'file1' ) # should be treated like ['file1']

How can my function tell whether a string or a list has been passed in? I know there is a type function, but is there a "more pythonic" way?


isinstance(your_var, basestring)

Well, there's nothing unpythonic about checking type. Having said that, if you're willing to put a small burden on the caller:

def func( *files ):
    for f in files:
         doSomethingWithFile( f )

func( *['file1','file2','file3'] ) #Is treated like func('file1','file2','file3')
func( 'file1' )

I'd argue this is more pythonic in that "explicit is better than implicit". Here there is at least a recognition on the part of the caller when the input is already in list form.


Personally, I don't really like this sort of behavior -- it interferes with duck typing. One could argue that it doesn't obey the "Explicit is better than implicit" mantra. Why not use the varargs syntax:

def func( *files ):
    for f in files:
        doSomethingWithFile( f )

func( 'file1', 'file2', 'file3' )
func( 'file1' )
func( *listOfFiles )

I would say the most Python'y way is to make the user always pass a list, even if there is only one item in it. It makes it really obvious func() can take a list of files

def func(files):
    for cur_file in files:
        blah(cur_file)

func(['file1'])

As Dave suggested, you could use the func(*files) syntax, but I never liked this feature, and it seems more explicit ("explicit is better than implicit") to simply require a list. It's also turning your special-case (calling func with a single file) into the default case, because now you have to use extra syntax to call func with a list..

If you do want to make a special-case for an argument being a string, use the isinstance() builtin, and compare to basestring (which both str() and unicode() are derived from) for example:

def func(files):
    if isinstance(files, basestring):
        doSomethingWithASingleFile(files)
    else:
        for f in files:
            doSomethingWithFile(f)

Really, I suggest simply requiring a list, even with only one file (after all, it only requires two extra characters!)