Comment vérifier si la variable est une chaîne avec compatibilité Python 2 et 3

171

Je suis conscient que je peux utiliser: isinstance(x, str)en python-3.x mais je dois vérifier si quelque chose est une chaîne en python-2.x également. Fonctionnera-t-il isinstance(x, str)comme prévu dans python-2.x? Ou aurai-je besoin de vérifier la version et l'utilisation isinstance(x, basestr)?

Plus précisément, en python-2.x:

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

et python-3.x n'a pas u"foo"

Randall Hunt
la source
2
La syntaxe u "" pour les littéraux Unicode est réintroduite dans Python 3.3
jfs
Impair. Je reçois `` `` >>> isinstance (u "test", basestring) True `` `` sur Python 2.7.16
Darakian

Réponses:

209

Si vous écrivez du code compatible 2.x et 3.x, vous voudrez probablement en utiliser six :

from six import string_types
isinstance(s, string_types)
ecatmur
la source
Désolé, je suis un peu confus sur le résultat suivant. >>> isinstance(u"foo", string_types) True >>> isinstance(u"foo".encode("utf-8"), string_types) True Je m'attendais à ce que isinstance (u "foo", string_types) retourne false.
Chandler.Huang
1
@ Chandler.Huang cette question concerne l'identification stret unicodesur Python 2, ou strsur Python 3. Si vous ne voulez unicodepas compter sur Python 2, utilisez simplement str.
ecatmur
@ecatmur woops, merci! supprimé, donc personne ne se confond
runDOSrun
4
vous pouvez également l'utiliser à partir du futurepackage au lieu de six:from future.utils import string_types
SuperGeo
113

L'approche la plus laconique que j'ai trouvée sans compter sur des packages comme six, est:

try:
  basestring
except NameError:
  basestring = str

puis, en supposant que vous ayez vérifié les chaînes dans Python 2 de la manière la plus générique,

isinstance(s, basestring)

fonctionnera désormais également pour Python 3+.

hbristow
la source
10
Pour py3, basestring = (str, bytes)derequests/compat.py
Tanky Woo
Bien, mais pourquoi? Ce serait bien si Python3 était rétrocompatible ici. Les solutions ci-dessus fonctionnent. Ce serait encore mieux s'il n'y en avait pas besoin.
guettli
2
Pour satisfaire à la fois le support py2 & 3 et mypy, j'ai fini avecif not hasattr(__builtins__, "basestring"): basestring = (str, bytes)
Dave Lee
35

Qu'en est-il, fonctionne dans tous les cas?

isinstance(x, ("".__class__, u"".__class__))
Fil
la source
@holdenweb: Non et oui - un astucieux "n'a d'impact que là où c'est nécessaire", je pense.
Dilettant
1
La raison pour laquelle j'aime cette réponse est qu'elle est compatible avec la migration de python2 vers 3.
Tiagojdferreira
4
J'ai également opté pour cette option, l'enveloppant dans une fonction d'assistance, de sorte qu'elle n'apparaisse qu'une seule fois, et il y a une place dans la docstring pour créditer Fil.
Carl Smith
2
Neat, et je l'utilisais moi-même, jusqu'à ce que je réalise que j'ai aussi from __future__ import unicode_literalsactif. Maintenant, je vais avec:isinstance(val, (str, u"".__class__))
Graham Klyne
18

C'est la réponse de @Lev Levitsky, un peu réécrite.

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

Le test try/ exceptest effectué une fois, puis définit une fonction qui fonctionne toujours et qui est aussi rapide que possible.

EDIT: En fait, nous n'avons même pas besoin d'appeler isinstance(); nous avons juste besoin d'évaluer basestringet de voir si nous obtenons un NameError:

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

Je pense que c'est plus facile à suivre avec l'appel à isinstance(), cependant.

Steveha
la source
isinstance("", basestring)est ce que je voulais dire par «appeler». Quoi qu'il en soit, +1.
Lev Levitsky
1
Python est un langage très dynamique, et je ne pense pas que ce soit mal du tout d'avoir un test comme celui-là. C'est une technique utile pour comprendre quelque chose une fois, et sur cette base, pour configurer une fonction qui sera toujours correcte. Merci pour le +1.
steveha
5
Je l' try: string_types = basestring except NameError: string_types = str
écrirais
12

La futurebibliothèque ajoute (à Python 2) des noms compatibles , afin que vous puissiez continuer à écrire Python 3 . Vous pouvez simplement faire ce qui suit:

from builtins import str
isinstance(x, str) 

Pour l'installer , exécutez simplementpip install future .

En mise en garde , il ne supporte que python>=2.6, >=3.3mais il est plus moderne que six, qui ne recommandé en cas d' utilisationpython 2.5

toto_tico
la source
8

Peut-être utiliser une solution de contournement comme

def isstr(s):
    try:
        return isinstance(s, basestring)
    except NameError:
        return isinstance(s, str)
Lev Levitsky
la source
Désolé de vous déranger mais isinstance(u'hello', basestr)cède SyntaxError: invalid syntaxpour moi avec Python 3.2.3 sous Windows 7 .. une idée pourquoi cela serait? Il ne semble pas aimer le u- j'obtiens cette erreur avec stretbasestr
Levon
1
@Levon Pas de problème :) C'est parce que Python3 n'a pas cette syntaxe , comme strdans Python3 est par définition Unicode. En conséquence, il n'y a pas de basestringtype, d'où le NameErrorqui est pris dans mon extrait.
Lev Levitsky
Il a cette syntaxe comme un noop maintenant. en 3.3
Randall Hunt
2
Je suggérerais de faire le test try/ exceptune seule fois, et en fonction des résultats de ce test unique, vous définissez isstr()correctement. Il n'est pas nécessaire d'engager la surcharge d'une exception pour chaque appel à isstr().
steveha
@Ranman a raison à propos de Python 3.3, voici un lien vers le PEP .
Lev Levitsky
7

Vous pouvez obtenir la classe d'un objet en appelant object.__class__, donc pour vérifier si object est le type de chaîne par défaut:

    isinstance(object,"".__class__)

Et vous pouvez placer ce qui suit en haut de votre code afin que les chaînes entre guillemets soient en unicode en python 2:

    from __future__ import unicode_literals
Martin Hansen
la source
Je cette solution un peu. J'ai trouvé qu'il peut être utile de définir str = "" .__ class__, qui permet désormais d'écrire normalement isinstance (objet, str) et garantit également que str (objet) retournera une chaîne unicode à la fois dans Python 2 et Python 3.
amicitas
Cela ne fonctionne pas lors de l'analyse XML: some_element.textest un 'str' mais la comparaison avec 'unicode' échouerait
coffre
Ne fonctionne pas avec la chaîne Unicode sur python 2: isinstance (u'XXX ',' '.__ class__) == False
Fil
0

Vous pouvez essayer ceci au début de votre 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

et plus tard dans le code:

anystring = "test"
# anystring = 1
if isinstance(anystring, basstring):
    print("This is a string")
else:
    print("No string")
bunkus
la source
0

Faites attention! En python 2, stret bytessont essentiellement les mêmes. Cela peut provoquer un bug si vous essayez de faire la distinction entre les deux.

>>> size = 5    
>>> byte_arr = bytes(size)
>>> isinstance(byte_arr, bytes)
True
>>> isinstance(byte_arr, str)
True
Fardin
la source
-4

type (chaîne) == str

renvoie true si c'est une chaîne, et false sinon

confused_programmer241
la source
1
Pas vrai pour Python 2, où stringest une chaîne Unicode
lxop