186

I'm aware that I can use: isinstance(x, str) in python-3.x but I need to check if something is a string in python-2.x as well. Will isinstance(x, str) work as expected in python-2.x? Or will I need to check the version and use isinstance(x, basestr)?

Specifically, in python-2.x:

>>>isinstance(u"test", str)
False

and python-3.x does not have u"foo"

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
Randall Hunt
  • 12,132
  • 6
  • 32
  • 42

10 Answers10

221

If you're writing 2.x-and-3.x-compatible code, you'll probably want to use six:

from six import string_types
isinstance(s, string_types)
ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • Sorry I am a bit confuse about the following result. `>>> isinstance(u"foo", string_types)` `True` `>>> isinstance(u"foo".encode("utf-8"), string_types)` `True` I was expecting isinstance(u"foo", string_types) return false. – Chandler.Huang Mar 31 '16 at 03:21
  • 2
    @Chandler.Huang this question is about identifying `str` and `unicode` on Python 2, or `str` on Python 3. If you don't want `unicode` to count on Python 2, just use `str`. – ecatmur Mar 31 '16 at 08:42
  • @ecatmur woops, thanks! deleted it, so noone gets confused – runDOSrun Sep 29 '17 at 18:20
  • 6
    you can also use it from `future` package instead of `six`: `from future.utils import string_types` – SuperGeo Jun 24 '18 at 19:36
128

The most terse approach I've found without relying on packages like six, is:

try:
  basestring
except NameError:
  basestring = str

then, assuming you've been checking for strings in Python 2 in the most generic manner,

isinstance(s, basestring)

will now also work for Python 3+.

hbristow
  • 1,896
  • 1
  • 12
  • 9
  • 11
    For py3, `basestring = (str, bytes)` from `requests/compat.py` – Tanky Woo Jan 17 '16 at 03:56
  • Nice, but why? It would be nice if Python3 would be backward-compatible here. Above solutions works. Would be even better, if there would be no need for it. – guettli Mar 04 '19 at 19:37
  • 2
    To satisfy both py2 &3 support and mypy, I ended up with `if not hasattr(__builtins__, "basestring"): basestring = (str, bytes)` – Dave Lee Apr 11 '19 at 03:33
41

What about this, works in all cases?

isinstance(x, ("".__class__, u"".__class__))
Fil
  • 1,766
  • 1
  • 15
  • 15
  • @holdenweb: No and yes - a nifty "only impacts where needed" hack I think. – Dilettant Mar 31 '17 at 19:10
  • 2
    The reason why I like this answer is that it is friendly with migrating from python2 to 3. – Tiagojdferreira Jan 18 '18 at 10:11
  • 4
    I also went with this option, wrapping it in a helper function, so it only appears once, and there's a place in the docstring to credit Fil. – Carl Smith May 21 '18 at 12:27
  • 2
    Neat, and I was using it myself, until I realized that I also have `from __future__ import unicode_literals` active. Now I'm going with: `isinstance(val, (str, u"".__class__))` – Graham Klyne Aug 23 '18 at 15:33
  • Not _quite_ all cases, in python 3 this is just unicode strings twice. If you want to include byte strings and unicode strings in both python versions, the first one also needs a prefix: `(b''.__class__, u''.__class__)`, and if you only want unicode strings then just `u''.__class__` is sufficient. Anyway, I needed this style because I also needed to detect byte strings and six's `string_types` didn't work. – Izkata Aug 09 '22 at 20:11
19

This is @Lev Levitsky's answer, re-written a bit.

try:
    isinstance("", basestring)
    def isstr(s):
        return isinstance(s, basestring)
except NameError:
    def isstr(s):
        return isinstance(s, str)

The try/except test is done once, and then defines a function that always works and is as fast as possible.

EDIT: Actually, we don't even need to call isinstance(); we just need to evaluate basestring and see if we get a NameError:

try:
    basestring  # attempt to evaluate basestring
    def isstr(s):
        return isinstance(s, basestring)
except NameError:
    def isstr(s):
        return isinstance(s, str)

I think it is easier to follow with the call to isinstance(), though.

steveha
  • 74,789
  • 21
  • 92
  • 117
  • `isinstance("", basestring)` is what I meant by "calling". Anyway, +1. – Lev Levitsky Jul 02 '12 at 22:05
  • 1
    Python is a very dynamic language, and I don't think it looks bad at all to have a test like that. This is a useful technique for figuring something out one time, and based on that, setting up a function that will always be correct. Thanks for the +1. – steveha Jul 02 '12 at 22:16
  • 5
    I'd write it as: `try: string_types = basestring except NameError: string_types = str` – jfs Jul 04 '12 at 15:06
11

The future library adds (to Python 2) compatible names, so you can continue writing Python 3. You can simple do the following:

from builtins import str
isinstance(x, str) 

To install it, just execute pip install future.

As a caveat, it only support python>=2.6,>=3.3, but it is more modern than six, which is only recommended if using python 2.5

toto_tico
  • 17,977
  • 9
  • 97
  • 116
8

Maybe use a workaround like

def isstr(s):
    try:
        return isinstance(s, basestring)
    except NameError:
        return isinstance(s, str)
Lev Levitsky
  • 63,701
  • 20
  • 147
  • 175
  • Sorry to bug you but `isinstance(u'hello', basestr)` yields `SyntaxError: invalid syntax` for me with Python 3.2.3 under Window 7 .. any idea why this would be? It doesn't seem to like the `u` - I get this error with `str` and `basestr` – Levon Jul 02 '12 at 21:22
  • 1
    @Levon No problem :) That's because [Python3 doesn't have that syntax](http://docs.python.org/release/3.0.1/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit), as `str` in Python3 is by definition Unicode. Accordingly, there's no `basestring` type, hence the `NameError` that is caught in my snippet. – Lev Levitsky Jul 02 '12 at 21:26
  • It does have that syntax as a noop now. in 3.3 – Randall Hunt Jul 02 '12 at 21:29
  • 2
    I would suggest doing the `try`/`except` test a single time, and based on the results of that single test, you define `isstr()` correctly. There is no need to incur the overhead of an exception for every call to `isstr()`. – steveha Jul 02 '12 at 21:31
  • @Ranman is right about Python 3.3, here's a link to [the PEP](http://www.python.org/dev/peps/pep-0414/). – Lev Levitsky Jul 02 '12 at 21:33
  • @steveha Good point, but that would kinda look bad, as one would have to actually call the function once for the exception to be raised. – Lev Levitsky Jul 02 '12 at 21:35
  • @LevLevitsky, it is not necessary to call the function to test which way to define the function. Okay, I'll post this as an answer since code looks bad in a comment. – steveha Jul 02 '12 at 21:57
  • Levon said it raised a Syntax error, not a NameError. It does that because it's `basestring` and not `basestr` – Tatarize Jul 17 '19 at 00:15
8

You can get the class of an object by calling object.__class__, so in order to check if object is the default string type:

    isinstance(object,"".__class__)

And You can place the following in the top of Your code so that strings enclosed by quotes are in unicode in python 2:

    from __future__ import unicode_literals
Martin Hansen
  • 597
  • 6
  • 5
  • 1
    I this solution quite a bit. I found it can be useful to define str = "".__class__, which now allows isinstance(object, str) to be written normally, and also ensures that str(object) will return a unicode string in both Python 2 and Python 3. – amicitas Dec 05 '13 at 14:10
  • This doesn't work when parsing XML: `some_element.text` is a 'str' but the compare with 'unicode' would fail – vault Jul 24 '15 at 13:12
  • Does't work with unicode string on python 2: isinstance(u'XXX', ''.__class__) == False – Fil Nov 13 '15 at 18:41
1

You can try this at the beginning of your code:

from __future__ import print_function
import sys
if sys.version[0] == "2":
    py3 = False
else:
    py3 = True
if py3: 
    basstring = str
else:
    basstring = basestring

and later in the code:

anystring = "test"
# anystring = 1
if isinstance(anystring, basstring):
    print("This is a string")
else:
    print("No string")
bunkus
  • 975
  • 11
  • 19
1

Be careful! In python 2, str and bytes are essentially the same. This can cause a bug if you are trying to distinguish between the two.

>>> size = 5    
>>> byte_arr = bytes(size)
>>> isinstance(byte_arr, bytes)
True
>>> isinstance(byte_arr, str)
True
Fardin Abdi
  • 1,284
  • 15
  • 20
-5

type(string) == str

returns true if its a string, and false if not