What is the Pythonic Way of Differentiating Between a String and a List?
Question:
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?
Answers:
You can use types module:
import types
if type(ls) == types.ListType:
#your code for list objects here
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"
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.
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
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")
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]
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?
You can use types module:
import types
if type(ls) == types.ListType:
#your code for list objects here
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"
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.
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
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")
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]