29

How to check if an object is a list of strings? I could only check if an object is string as such:

def checktype(obj):
  if isinstance(obj,str):
    print "It's a string"

obj1 = ['foo','bar','bar','black','sheet']
obj2 = [1,2,3,4,5,'bar']
obj3 = 'bar'

for i in [obj1,obj2,obj3]:
  checktype(i)

Desired output:

It's a list of strings
It's not a list of strings or a single string
It's a single string
5
  • 3
    For clarity I would rename checktype to is_list_of_string. Commented Aug 28, 2013 at 18:11
  • 4
    One edge case to consider: Is [] a list of strings, or not? Commented Aug 28, 2013 at 18:15
  • nope [] wouldn't be a list of string, it's an empty list. Commented Aug 28, 2013 at 18:36
  • 2
    @2er0: OK. Usually people want to consider [] a valid list of 0 anythings, so that's what functions like all do. So an answer that just relies on all (like Sukrit Kalra's current version) is going to return True rather than False in that case. The simplest fix is to do if obj and [rest of check]. Commented Aug 28, 2013 at 18:47
  • [] is a valid empty list of strings. I have checked it by validating and it works fine. Commented Nov 29, 2022 at 9:38

6 Answers 6

29

Something like this, I presume? You could do some checks to see if it's a single string.

>>> def checktype(obj):
        return bool(obj) and all(isinstance(elem, basestring) for elem in obj)

>>> obj1 = ['foo','bar','bar','black','sheet']
>>> obj2 = [1,2,3,4,5,'bar']
>>> obj3 = 'bar'
>>> for i in [obj1, obj2, obj3] :
        print checktype(i)


True
False
True

Why check for basestring instead of str?

You should check for basestring instead of str since it's a common class from which both the str and unicode types inherit from. Checking only the str leaves out the unicode types.

As per Steven Rumbalski's suggestions, if you need to specifically check for a list of strings, you could do.

>>> def is_list_of_strings(lst):
        return bool(lst) and not isinstance(lst, basestring) and all(isinstance(elem, basestring) for elem in lst)
        # You could break it down into `if-else` constructs to make it clearer to read.

>>> for i in [obj1, obj2, obj3] :
        print is_list_of_strings(i)


True
False
False

EDIT - As per abarnert's suggestion, you could also check for a list instead of not isinstance(lst, basestring), the code would get rewritten as.

>>> def is_list_of_strings(lst):
        return bool(lst) and isinstance(lst, list) and all(isinstance(elem, basestring) for elem in lst)
        # You could break it down into `if-else` constructs to make it clearer to read.

>>> for i in [obj1, obj2, obj3] :
        print is_list_of_strings(i)


True
False
False

Moving away from one liners, we could use.

>>> def is_list_of_strings(lst):
        if lst and isinstance(lst, list):
            return all(isinstance(elem, basestring) for elem in lst)
        else:
            return False
Sign up to request clarification or add additional context in comments.

12 Comments

Specification says to test for a list of strings, so checktype('bar') should return False. Good job using basestring.
Actually, I think it would be better to check isinstance(lst, list) than not isinstance(lst, basestring). After all, a dict mapping strings to strings isn't a list of strings any more than a string is… But otherwise, great answer.
I'm surprised you didn't notice the simpler version of @abarnert's suggestion: return isinstance(lst, list) and all(isinstance(elem, basestring) for elem in lst)
I liked that you had split it up. I thought it was more readable that way. To each their own. Either way, it's acceptable to revise your original answer. That might be clearer than tacking edits to the end.
From Python 3 on, you just check for isinstance(lst, str)
|
23

To test if all the items in a list are strings, use the all built-in and a generator:

if all(isinstance(s, str) for s in lis):

Note though that, if your list is empty, this will still return True since that is technically a list of 0 strings. However, since you want to consider [] as being False, you will need to do this:

if lis and all(isinstance(s, str) for s in lis):

So, your function should be something like this:

def checktype(obj):
    # This if statement makes sure input is a list that is not empty
    if obj and isinstance(obj, list): 
        return all(isinstance(s, str) for s in obj)
    else:
        return False

This function will only return True if its input is a list that is not empty and that is composed entirely of strings. Anything else (such as [], ['a', 1], ('a', 'b'), etc) will make it return False.

Also, using all in this way has an added bonus in that it stops checking on the first item it finds that returns False (is not a string). This allows you to work with very large lists quite efficiently.

7 Comments

Good answer, but change the instance check from str to basestr.
… unless, of course, the OP really meant "list of str" rather than "list of strings"… which is possible, but he didn't say that's what he wanted. (@StevenRumbalski explains this pretty well in his answer, so I don't think it's necessary to explain it again here.)
Well, I went with str because, in the OP's post, he was checking if it was type str, not basestring.
Sorry, I meant Sukrit Kalra's answer, not Steven Rumbalski's. I should have known that an @ and an s would only autocomplete to people who'd commented on this answer, not to everyone on this page…
This doesn't quite "return True if its input is a list that is not empty and that is composed entirely of strings". If the input is an empty list, it returns the input. This may be especially surprising if the input has something added to it while the return value is still being used.
|
3

This answer is for Python 3. If for example the variable name is pins:

if not (pins and isinstance(pins, list) and all(isinstance(pin, str) for pin in pins)):
    raise TypeError('pins must be a list of one or more strings.')

It checks for three things:

  1. Is is non-empty?
  2. Is it a list?
  3. Does it contain strings?

If you also need to check for uniqueness of the strings, include this fourth check:

and (len(pins) == len(set(pins)))

Comments

3

As a one liner:

assert all(map(lambda x: isinstance(x, str), my_list))

Comments

1

The answers I've read so far raise exepctions when given a non-list that isn't a string...and isn't iterable either. That question is addressed in:

In Python, how do I determine if an object is iterable?

Taking the duck-typing approach:

def categorize(x):
    result = "not a string or list of strings"
    if isinstance(x, basestring):
        return "It's a single string"
    try:
        if all(isinstance(y, basestring) for y in x):
            return "It's a list of strings"
    except TypeError:
        pass
    return "It's not a list of strings or a single string"

data = [ 5, "xyzzy", list("xyzzy"), ['1', '23', 456]]
for x in data:
    print x, categorize(x)

Output:

5 It's not a list of strings or a single string
xyzzy It's a single string
['x', 'y', 'z', 'z', 'y'] It's a list of strings
['1', '23', 456] It's not a list of strings or a single string

Comments

0

You may also convert all elements to str: list(map(str, [1,2,3]))

Result: ['1', '2', '3']

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.