Comment savoir si un objet Python est une chaîne?

402

Comment puis-je vérifier si un objet Python est une chaîne (régulière ou Unicode)?

Matt S.
la source
18
Ce à quoi Jason fait référence, c'est la frappe de canard (s'il plie comme un canard, c'est probablement un canard). En Python, vous "laissez souvent votre code fonctionner" sur n'importe quel objet de type chaîne sans tester s'il s'agit d'une chaîne ou d'une sous-classe de chaîne. Pour plus d'informations, voir: docs.python.org/glossary.html#term-duck-typing
Ben Hoyt
4
C'est ce que j'aime chez SO. Je pose habituellement une question, sans réponse, les gens me disent que je ne devrais pas faire ça de toute façon et pourquoi, et je grandis en tant que programmeur. =)
physicsmichael
24
+1: Ce n'est pas parce qu'une réponse est rarement nécessaire que la question n'est pas valide. Bien que je pense qu'il est bon d'avoir une mise en garde ici, je ne pense pas que cela mérite de rétrograder la question.
Trevor
17
Il s'agit probablement de l'utilisation la plus légitime de la vérification de type en Python. Les chaînes sont itérables, donc les distinguer des listes de toute autre manière est une mauvaise idée.
ojrac
3
Il y a certainement des cas où il est nécessaire de distinguer les chaînes des autres itérables. Par exemple, consultez le code source de PrettyPrinter dans le module pprint.
saxman01

Réponses:

302

Python 2

À utiliser isinstance(obj, basestring)pour un objet à tester obj.

Docs .

John Fouhy
la source
178

Python 2

Pour vérifier si un objet oest un type chaîne d'une sous-classe d'un type chaîne:

isinstance(o, basestring)

parce que les deux stret unicodesont des sous-classes de basestring.

Pour vérifier si le type de oest exactement str:

type(o) is str

Pour vérifier s'il os'agit d'une instance strou d'une sous-classe de str:

isinstance(o, str)

Les éléments ci-dessus fonctionnent également pour les chaînes Unicode si vous les remplacez strpar unicode.

Cependant, vous n'aurez peut-être pas du tout besoin d'effectuer une vérification de type explicite. "Duck typing" peut répondre à vos besoins. Voir http://docs.python.org/glossary.html#term-duck-typing .

Voir aussi Quelle est la manière canonique de vérifier le type en python?

Matt S.
la source
variable locale 'str' référencée avant l'affectation
john ktejik
@johnktejik python3 vs python2. Vous devez vérifier basestringdans py2.
erikbwork
170

Python 3

En Python 3.x basestringn'est plus disponible, tout comme strle seul type de chaîne (avec la sémantique de Python 2.x unicode).

Donc, la vérification dans Python 3.x est juste:

isinstance(obj_to_test, str)

Cela suit le correctif de l' 2to3outil de conversion officiel : conversion basestringen str.

sevenforce
la source
94

Python 2 et 3

(compatibilité croisée)

Si vous souhaitez vérifier sans tenir compte de la version Python (2.x vs 3.x), utilisez six( PyPI ) et son string_typesattribut:

import six

if isinstance(obj, six.string_types):
    print('obj is a string!')

Dans six(un module à fichier unique très léger), il fait simplement ceci :

import sys
PY3 = sys.version_info[0] == 3

if PY3:
    string_types = str
else:
    string_types = basestring
Nick T
la source
Alternativement, vous pouvez utiliser future( PyPI ) pour conserver même le nom:from past.builtins import basestring
David Nemeskey
1
BTW the Cheat Sheet est une excellente ressource pour la compatibilité des versions Python.
David Nemeskey
1
Qu'en est-il de ne pas utiliser d'importations? Essayez d'abord basestring, puis retombez str. Par exempledef is_string(obj): try: return isinstance(obj, basestring) # python 2 except NameError: return isinstance(obj, str) # python 3
isaacbernat
19

J'ai trouvé cela et plus encore pythonic:

if type(aObject) is str:
    #do your stuff here
    pass

puisque les objets type sont singleton, is peut être utilisé pour comparer l'objet au type str

Zhou Jingyuan
la source
4
Ce n'est pas la méthode généralement recommandée pour tester le type, en raison de l'héritage: isinstance(obj_to_test, str)est évidemment destiné à tester pour le type, et il a l'avantage d'utiliser la même procédure que pour les autres cas, non str.
Eric O Lebigot
14

Si l'on veut éviter la vérification de type explicite (et il y a de bonnes raisons de s'en éloigner), la partie la plus sûre du protocole de chaîne à vérifier est probablement:

str(maybe_string) == maybe_string

Il ne sera pas par un itérer itérables ou iterator, il ne sera pas appeler une liste de chaînes comme une chaîne et il détecte correctement un type corde comme une chaîne.

Bien sûr, il y a des inconvénients. Par exemple, str(maybe_string)peut être un calcul lourd. Comme souvent, la réponse est que cela dépend .

EDIT: Comme @Tcll le souligne dans les commentaires, la question demande en fait un moyen de détecter à la fois les chaînes unicode et les bytestrings. Sur Python 2, cette réponse échouera avec une exception pour les chaînes unicode qui contiennent des caractères non ASCII, et sur Python 3, elle retournera Falsepour tous les bytestrings.

clacke
la source
Dans le cas d'objets qui s'initialisent avec des données de représentation, cela peut ne pas fonctionner comme prévu ... b = b'test'; r = str(b) == bbcontient les mêmes données que str(b)mais (étant un objet octets) ne valide pas en tant que chaîne.
Tcll
@Tcll À droite, la question dit en fait "soit régulière ou Unicode". Je suppose que je ne l'ai pas lu correctement.
clacke
11

Afin de vérifier si votre variable est quelque chose, vous pouvez aller comme:

s='Hello World'
if isinstance(s,str):
#do something here,

La sortie de isistance vous donnera une valeur booléenne True ou False afin que vous puissiez l'ajuster en conséquence. Vous pouvez vérifier l'acronyme attendu de votre valeur en utilisant initialement: type (s) Cela vous renverra "str" ​​afin que vous puissiez l'utiliser dans la fonction isistance.

Abraam Georgiadis
la source
5

Je pourrais traiter cela dans le style de frappe de canard, comme d'autres le mentionnent. Comment savoir qu'une chaîne est vraiment une chaîne? eh bien, évidemment en le convertissant en chaîne!

def myfunc(word):
    word = unicode(word)
    ...

Si l'argument est déjà une chaîne ou un type unicode, real_word conservera sa valeur non modifiée. Si l'objet passé implémente une __unicode__méthode, celle-ci est utilisée pour obtenir sa représentation unicode. Si l'objet transmis ne peut pas être utilisé en tant que chaîne, la fonction unicodeintégrée déclenche une exception.

SingleNegationElimination
la source
3
isinstance(your_object, basestring)

sera True si votre objet est en effet de type chaîne. 'str' est un mot réservé.

mes excuses, la bonne réponse utilise «basestring» au lieu de «str» afin d'inclure également les chaînes unicode - comme cela a été noté ci-dessus par l'un des autres répondants.

bip Bip
la source
Ne fonctionne pas pour les objets Unicode, qui étaient explicitement demandés dans la question.
dbn
1

Ce soir, je suis tombé sur une situation dans laquelle je pensais que j'allais devoir vérifier le strtype, mais il s'est avéré que non.

Mon approche pour résoudre le problème fonctionnera probablement dans de nombreuses situations, donc je l'offre ci-dessous au cas où d'autres personnes lisant cette question seraient intéressées (Python 3 uniquement).

# NOTE: fields is an object that COULD be any number of things, including:
# - a single string-like object
# - a string-like object that needs to be converted to a sequence of 
# string-like objects at some separator, sep
# - a sequence of string-like objects
def getfields(*fields, sep=' ', validator=lambda f: True):
    '''Take a field sequence definition and yield from a validated
     field sequence. Accepts a string, a string with separators, 
     or a sequence of strings'''
    if fields:
        try:
            # single unpack in the case of a single argument
            fieldseq, = fields
            try:
                # convert to string sequence if string
                fieldseq = fieldseq.split(sep)
            except AttributeError:
                # not a string; assume other iterable
                pass
        except ValueError:
            # not a single argument and not a string
            fieldseq = fields
        invalid_fields = [field for field in fieldseq if not validator(field)]
        if invalid_fields:
            raise ValueError('One or more field names is invalid:\n'
                             '{!r}'.format(invalid_fields))
    else:
        raise ValueError('No fields were provided')
    try:
        yield from fieldseq
    except TypeError as e:
        raise ValueError('Single field argument must be a string'
                         'or an interable') from e

Quelques tests:

from . import getfields

def test_getfields_novalidation():
    result = ['a', 'b']
    assert list(getfields('a b')) == result
    assert list(getfields('a,b', sep=',')) == result
    assert list(getfields('a', 'b')) == result
    assert list(getfields(['a', 'b'])) == result
Rick soutient Monica
la source
1

C'est simple, utilisez le code suivant (nous supposons que l'objet mentionné est obj) -

if type(obj) == str:
    print('It is a string')
else:
    print('It is not a string.')
Abhijeet.py
la source
0

Vous pouvez le tester en concaténant avec une chaîne vide:

def is_string(s):
  try:
    s += ''
  except:
    return False
  return True

Modifier :

Correction de ma réponse après des commentaires soulignant que cela échoue avec les listes

def is_string(s):
  return isinstance(s, basestring)
georgepsarakis
la source
Vous avez raison, merci de l'avoir signalé. J'ai donné une réponse alternative.
georgepsarakis
-3

Pour une belle approche de type canard pour les chaînes de caractères qui a l'avantage de travailler avec Python 2.x et 3.x:

def is_string(obj):
    try:
        obj + ''
        return True
    except TypeError:
        return False

sagesse était proche du typage de canard avant de passer à l' isinstanceapproche, sauf que cela +=a une signification différente pour les listes +.

Alphadelta14
la source
2
Eh bien, vous avez deux downvotes et personne n'a fait de commentaire. Je n'ai pas dévalué mais je n'aime pas votre solution car: * Trop verbeux. Vous ne devriez pas avoir besoin de définir une fonction pour ce faire. * Coûteux. La capture d'exceptions n'est pas bonne pour les performances. * Erreur sujette. Un autre objet peut implémenter add , voir une chaîne et déclencher un autre type d'exception, qui n'est pas TypeError.
santiagobasulto
Ici aussi, vous utilisez l'approche de type canard, ce qui est beau, mais vous vous retrouvez avec une exception de lancer et d'attraper juste pour découvrir quelque chose, ce qui n'est pas beau.
Alexey Tigarev
Cela peut être légitimement le seul moyen infaillible de faire la distinction entre une chaîne semblable à une autre chaîne itérable. On pourrait rechercher des attributs comme isalpha, mais qui sait quelles méthodes seraient sûres de rechercher?
clacke
J'ai réalisé que la __str__méthode plus l'égalité peut en fait être à toute épreuve. Mais même cela n'est pas sans réserves.
clacke
Les exceptions @santiagobasulto sont bon marché en Python. Si vous vous attendez à l'erreur 1% du temps, cela trypeut être plus rapide. Si vous vous y attendez 99% du temps, peut-être pas. La différence de performances étant minime, il vaut mieux être idiomatique à moins de profiler votre code et de l'identifier comme étant réellement lent.
Nick T
-4
if type(varA) == str or type(varB) == str:
    print 'string involved'

d'EDX - cours en ligne MITx: 6.00.1x Introduction à l'informatique et à la programmation à l'aide de Python

William Clay
la source
6
C'est probablement la pire façon de vérifier. Non seulement il exclut les objets Unicode, il exclut même les sous-classes de str!
août