Cómo verificar si la variable es una cadena con compatibilidad con python 2 y 3

171

Soy consciente de que puedo usar: isinstance(x, str)en python-3.x, pero también necesito verificar si algo es una cadena en python-2.x. ¿ isinstance(x, str)Funcionará como se esperaba en python-2.x? ¿O tendré que verificar la versión y usarla isinstance(x, basestr)?

Específicamente, en python-2.x:

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

y python-3.x no tiene u"foo"

Randall Hunt
fuente
2
La sintaxis u "" para literales Unicode se reintroduce en Python 3.3
jfs
Impar. Obtengo `` `>>> isinstance (u" test ", basetring) True` `` en Python 2.7.16
Darakian

Respuestas:

209

Si está escribiendo código compatible con 2.xy 3.x, probablemente quiera usar seis :

from six import string_types
isinstance(s, string_types)
ecatmur
fuente
Lo siento, estoy un poco confundido sobre el siguiente resultado. >>> isinstance(u"foo", string_types) True >>> isinstance(u"foo".encode("utf-8"), string_types) True Esperaba que isinstance (u "foo", string_types) devuelva false.
Chandler.Huang
1
@ Chandler.Huang, esta pregunta se trata de identificar stry unicodeen Python 2, o stren Python 3. Si no desea unicodecontar con Python 2, simplemente use str.
ecatmur
@ecatmur woops, gracias! lo eliminó, para que nadie se confunda
runDOSrun
44
también puede usarlo desde el futurepaquete en lugar de six:from future.utils import string_types
SuperGeo
113

El enfoque más conciso que he encontrado sin depender de paquetes como seis, es:

try:
  basestring
except NameError:
  basestring = str

luego, suponiendo que haya estado buscando cadenas en Python 2 de la manera más genérica,

isinstance(s, basestring)

ahora también funcionará para Python 3+.

hbristow
fuente
10
Para py3, basestring = (str, bytes)derequests/compat.py
Tanky Woo
Bien, pero ¿por qué? Sería bueno si Python3 fuera compatible con versiones anteriores aquí. Las soluciones anteriores funcionan. Sería aún mejor, si no fuera necesario.
guettli
2
Para satisfacer tanto el soporte de py2 & 3 como mypy, terminé conif not hasattr(__builtins__, "basestring"): basestring = (str, bytes)
Dave Lee
35

¿Qué pasa con esto, funciona en todos los casos?

isinstance(x, ("".__class__, u"".__class__))
Fil
fuente
@holdenweb: No y sí, creo que un ingenioso truco "solo impacta donde sea necesario".
Dilettant
1
La razón por la que me gusta esta respuesta es que es amigable con la migración de python2 a 3.
Tiagojdferreira
44
También utilicé esta opción, envolviéndola en una función auxiliar, por lo que solo aparece una vez, y hay un lugar en la cadena de documentación para acreditar a Fil.
Carl Smith
2
Aseado, y lo estaba usando yo mismo, hasta que me di cuenta de que también tenía from __future__ import unicode_literalsactivo. Ahora voy con:isinstance(val, (str, u"".__class__))
Graham Klyne
18

Esta es la respuesta de @Lev Levitsky, reescrita un poco.

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

La prueba try/ exceptse realiza una vez y luego define una función que siempre funciona y es lo más rápida posible.

EDITAR: En realidad, ni siquiera necesitamos llamar isinstance(); solo necesitamos evaluar basestringy ver si obtenemos un NameError:

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

Sin embargo, creo que es más fácil seguir con la llamada isinstance().

steveha
fuente
isinstance("", basestring)es lo que quise decir con "llamar". De todos modos, +1.
Lev Levitsky
1
Python es un lenguaje muy dinámico, y no creo que se vea nada mal tener una prueba como esa. Esta es una técnica útil para resolver algo una vez, y en base a eso, configurar una función que siempre será correcta. Gracias por el +1.
steveha
55
Lo escribiría como:try: string_types = basestring except NameError: string_types = str
jfs
12

La futurebiblioteca agrega (a Python 2) nombres compatibles , por lo que puede continuar escribiendo Python 3 . Simplemente puede hacer lo siguiente:

from builtins import str
isinstance(x, str) 

Para instalarlo , solo ejecute pip install future.

Como advertencia , solo es compatible python>=2.6, >=3.3pero es más moderno que six, lo que solo se recomienda si se usapython 2.5

toto_tico
fuente
8

Tal vez use una solución como

def isstr(s):
    try:
        return isinstance(s, basestring)
    except NameError:
        return isinstance(s, str)
Lev Levitsky
fuente
Lamento molestarlo, pero me isinstance(u'hello', basestr)rinde SyntaxError: invalid syntaxcon Python 3.2.3 en la Ventana 7 ... ¿alguna idea de por qué esto sería? Parece que no le gusta el u- Me sale este error con strybasestr
Levon
1
@Levon No hay problema :) Eso es porque Python3 no tiene esa sintaxis , ya que stren Python3 es, por definición, Unicode. En consecuencia, no hay ningún basestringtipo, por lo tanto, eso NameErrorestá atrapado en mi fragmento.
Lev Levitsky
Tiene esa sintaxis como noop ahora. en 3.3
Randall Hunt
2
Sugeriría hacer la prueba try/ exceptuna sola vez, y en función de los resultados de esa prueba única, usted define isstr()correctamente. No es necesario incurrir en la sobrecarga de una excepción por cada llamada a isstr().
steveha
@Ranman tiene razón sobre Python 3.3, aquí hay un enlace a la PEP .
Lev Levitsky
7

Puede obtener la clase de un objeto llamando object.__class__, por lo que para verificar si el objeto es el tipo de cadena predeterminado:

    isinstance(object,"".__class__)

Y puede colocar lo siguiente en la parte superior de Su código para que las cadenas entre comillas estén en unicode en python 2:

    from __future__ import unicode_literals
Martin Hansen
fuente
Yo esta solución bastante. Descubrí que puede ser útil definir str = "" .__ class__, que ahora permite que isinstance (objeto, str) se escriba normalmente, y también garantiza que str (objeto) devolverá una cadena unicode en Python 2 y Python 3.
amicitas
Esto no funciona al analizar XML: some_element.textes un 'str' pero la comparación con 'unicode' fallaría
bóveda
No funciona con cadena Unicode en python 2: isinstance (u'XXX ',' '.__ class__) == False
Fil
0

Puedes probar esto al comienzo de tu código:

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

y luego en el código:

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

¡Ten cuidado! En python 2, stry bytesson esencialmente lo mismo. Esto puede causar un error si está tratando de distinguir entre los dos.

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

tipo (cadena) == cadena

devuelve verdadero si es una cadena y falso si no

confusión_programador241
fuente
1
No es cierto para Python 2, donde stringhay una cadena Unicode
lxop