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!)