34

For my program I have a lot of places where an object can be either a string or a list containing strings and other similar lists. These are generally read from a JSON file. They both need to be treated differently. Right now, I am just using isinstance, but that does not feel like the most pythonic way of doing it, so does anyone have a better way of doing it?

dreftymac
  • 31,404
  • 26
  • 119
  • 182
Nikwin
  • 6,576
  • 4
  • 35
  • 43
  • 1
    Possible duplicate: http://stackoverflow.com/questions/922774/check-if-input-is-a-list-tuple-of-strings-or-a-single-string – mavnn Jul 12 '10 at 10:19
  • @mavnn - You're right, and I've voted to close. The answer is "You're already doing it the Pythonic way." anyway. :-) – Omnifarious Jul 12 '10 at 10:24

6 Answers6

29

No need to import modules, isinstance(), str and unicode (versions before 3 -- there's no unicode in 3!) will do the job for you.

Python 2.x:

Python 2.6.1 (r261:67515, Feb 11 2010, 00:51:29) 
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> isinstance(u'', (str, unicode))
True
>>> isinstance('', (str, unicode))
True
>>> isinstance([], (str, unicode))
False

>>> for value in ('snowman', u'☃ ', ['snowman', u'☃ ']):
...     print type(value)
... 
<type 'str'>
<type 'unicode'>
<type 'list'>

Python 3.x:

Python 3.2 (r32:88445, May 29 2011, 08:00:24) 
[GCC 4.2.1 (Apple Inc. build 5664)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> isinstance('☃ ', str)
True
>>> isinstance([], str)
False

>>> for value in ('snowman', '☃ ', ['snowman', '☃ ']):
...     print(type(value))
... 
<class 'str'>
<class 'str'>
<class 'list'>

From PEP008:

Object type comparisons should always use isinstance() instead of comparing types directly.

johnsyweb
  • 136,902
  • 23
  • 188
  • 247
  • 1
    People should be discouraged from using basestring nowadays because it doesn't exist in Python 3. – Omnifarious Jul 12 '10 at 10:24
  • 2
    you could emulate this behaviour in Python 3 with `basestring = str`. But that's about it I suppose. – Wolph Jul 12 '10 at 10:44
  • 1
    The second argument to `isinstance` can be a tuple, so this would be better than checking against `basestring`: `isinstance(u'', (str, unicode))` – Jesse Dhillon Aug 15 '10 at 04:16
  • Here is the shortest answer: http://stackoverflow.com/a/26797688/99834 which works for both. – sorin Nov 07 '14 at 09:09
10

Since Python3 no longer has unicode or basestring, in this case ( where you are expecting either a list or a string) it's better to test against list

if isinstance(thing, list):
    # treat as list
else:
    # treat as str/unicode

as that is compatible with both Python2 and Python3

John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • 2
    What about if `thing` is a `tuple`, a `dict` or a `set`, etcetera? – johnsyweb Jul 12 '10 at 10:37
  • 2
    @Johnsyweb, if there was a possibility of other types then the answer would be different. This question says it is either a list or a string – John La Rooy Jul 12 '10 at 10:47
  • 2
    Dear downvoter, please consider leaving a comment so I can improve my answer – John La Rooy Jul 12 '10 at 13:17
  • Typically the object is either a single item or some container of items. It is usually better to test `isinstance(object, item_type)` so the code is not restricted to a single container type. – Jeyekomon Feb 15 '21 at 11:03
8

Another method, using the practice of "It's better to ask forgiveness than permission," duck-typing being generally preferred in Python, you could try to do what you want first, e.g.:

try:
    value = v.split(',')[0]
except AttributeError:  # 'list' objects have no split() method
    value = v[0]
knickum
  • 581
  • 1
  • 5
  • 8
  • Unlike the `isinstance` answers, this approach is better able to generalize to distinguish custom string types from other custom sequence types. – Christopher Bruns Nov 04 '20 at 17:55
3

Using isinstance:

On Python>=2.3 a string may be a str or unicode type. To check both cases:

if isinstance(a,basestring): # same as isinstance(obj, (str, unicode))
   print "Object is a string"

From Python 3 only one string type exists, so instead of basestring you should use str:

if isinstance(a,str):
   print "Object is a string"
zoli2k
  • 3,388
  • 4
  • 26
  • 36
1

As I like to keep things simple, here is the shortest form that is compatible with both 2.x and 3.x:

# trick for py2/3 compatibility
if 'basestring' not in globals():
   basestring = str

v = "xx"

if isinstance(v, basestring):
   print("is string")
sorin
  • 161,544
  • 178
  • 535
  • 806
-1

You can use types module:

import types
if type(ls) == types.ListType:
    #your code for list objects here
Mustafa Zengin
  • 2,885
  • 5
  • 21
  • 24
  • 1
    The preferred way of comparing types is by using `isinstance` or otherwise with the `is` operator. http://docs.python.org/library/types.html – Wolph Jul 12 '10 at 10:20
  • You can use `type(ls) is list` however that won't work for subclasses of list – John La Rooy Jul 12 '10 at 10:25
  • @Lars Wirzenius: No. That attempts to invoke a comparison of some kind, and while the default comparison for objects of type `type` is to compare object ids, and this results in identical behavior to `is`, it's not guaranteed. In this case `is` or preferably `isinstance` is the right answer. – Omnifarious Jul 12 '10 at 10:26