Como verificar se a variável é string com compatibilidade com python 2 e 3

171

Estou ciente de que posso usar: isinstance(x, str)no python-3.x, mas preciso verificar se algo também é uma string no python-2.x. Funcionará isinstance(x, str)como esperado no python-2.x? Ou precisarei verificar a versão e usar isinstance(x, basestr)?

Especificamente, em python-2.x:

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

e python-3.x não possui u"foo"

Randall Hunt
fonte
2
u "" sintaxe para literais Unicode é reintroduzido em Python 3.3
jfs
Ímpar. Eu recebo `` >>> isinstance (u "test", basestring) True `` `no Python 2.7.16
Darakian

Respostas:

209

Se você estiver escrevendo um código compatível com 2.x e 3.x, provavelmente precisará usar seis :

from six import string_types
isinstance(s, string_types)
ecatmur
fonte
Desculpe, estou um pouco confuso com o seguinte resultado. >>> isinstance(u"foo", string_types) True >>> isinstance(u"foo".encode("utf-8"), string_types) True Eu esperava que isinstance (u "foo", string_types) retornasse false.
Chandler.Huang
1
@ Chandler.Huang esta pergunta é sobre identificação stre unicodeno Python 2, ou strno Python 3. Se você não quiser unicodecontar com o Python 2, basta usar str.
Ecatmur 31/03/16
@ecatmur woops, obrigado! excluída, então ninguém fica confuso
runDOSrun
4
você também pode usá-lo a partir do futurepacote em vez de six:from future.utils import string_types
SuperGeo 24/06
113

A abordagem mais concisa que encontrei sem depender de pacotes como seis é:

try:
  basestring
except NameError:
  basestring = str

então, supondo que você tenha verificado as strings no Python 2 da maneira mais genérica,

isinstance(s, basestring)

agora também funcionará para o Python 3+.

hbristow
fonte
10
Para py3, basestring = (str, bytes)derequests/compat.py
Tanky Woo 17/01
Legal, mas por quê? Seria bom se o Python3 fosse compatível com versões anteriores aqui. As soluções acima funcionam. Seria ainda melhor, se não houvesse necessidade disso.
guettli
2
Para satisfazer tanto PY2 e 3 apoio e mypy, acabei comif not hasattr(__builtins__, "basestring"): basestring = (str, bytes)
Dave Lee
35

E sobre isso, funciona em todos os casos?

isinstance(x, ("".__class__, u"".__class__))
Fil
fonte
@holdenweb: Não e sim - um astuto "apenas afeta onde necessário" hackear, eu acho.
Diletant 31/03
1
A razão pela qual eu gosto de esta resposta é que é amigável com a migração do python2 a 3.
Tiagojdferreira
4
Também usei essa opção, envolvendo-a em uma função auxiliar, para que apareça apenas uma vez e haja um lugar na doutrina para creditar a Fil.
Carl Smith
2
Legal, e eu estava usando sozinho, até perceber que também tenho from __future__ import unicode_literalsatividade. Agora eu vou com:isinstance(val, (str, u"".__class__))
Graham Klyne
18

Esta é a resposta de @Lev Levitsky, reescrita um pouco.

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

O try/ excepttest é feito uma vez e, em seguida, define uma função que sempre funciona e é o mais rápido possível.

EDIT: Na verdade, nem precisamos ligar isinstance(); só precisamos avaliar basestringe ver se temos um NameError:

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

Eu acho que é mais fácil seguir com a chamada para isinstance(), no entanto.

steveha
fonte
isinstance("", basestring)é o que eu quis dizer com "chamando". Enfim, +1.
Lev Levitsky
1
Python é uma linguagem muito dinâmica, e não acho que seja ruim fazer um teste como esse. Essa é uma técnica útil para descobrir algo uma vez e, com base nisso, configurar uma função que sempre estará correta. Obrigado pelo +1.
Steveha
5
Eu escreveria como:try: string_types = basestring except NameError: string_types = str
jfs
12

A futurebiblioteca adiciona (ao Python 2) nomes compatíveis , para que você possa continuar escrevendo o Python 3 . Você pode simplesmente fazer o seguinte:

from builtins import str
isinstance(x, str) 

Para instalá-lo , basta executar pip install future.

Como ressalva , ele só apoiar python>=2.6, >=3.3mas é mais moderno do que six, o que só é recomendado se estiver usandopython 2.5

toto_tico
fonte
8

Talvez use uma solução alternativa como

def isstr(s):
    try:
        return isinstance(s, basestring)
    except NameError:
        return isinstance(s, str)
Lev Levitsky
fonte
Desculpe incomodá-lo, mas me isinstance(u'hello', basestr)rende SyntaxError: invalid syntaxcom o Python 3.2.3 na Janela 7 .. alguma idéia do porquê? Não parece gostar do u- recebo esse erro com strebasestr
Levon 2/12
1
@ Levon Sem problemas :) Isso porque Python3 não tem essa sintaxe , como strem Python3 é por definição Unicode. Consequentemente, não há nenhum basestringtipo, daí o NameErrorque está capturado no meu trecho.
Lev Levitsky
Ele tem essa sintaxe como um noop agora. em 3.3
Randall Hunt
2
Eu sugeriria fazer o try/ excepttest uma única vez e, com base nos resultados desse único teste, você define isstr()corretamente. Não há necessidade de gerar uma exceção para todas as chamadas isstr().
Steveha
@Ranman está certo sobre Python 3.3, aqui está um link para o PEP .
Lev Levitsky
7

Você pode obter a classe de um objeto chamando object.__class__, portanto, para verificar se o objeto é o tipo de string padrão:

    isinstance(object,"".__class__)

E você pode colocar o seguinte na parte superior do seu código, para que as seqüências de caracteres entre aspas estejam em unicode no python 2:

    from __future__ import unicode_literals
Martin Hansen
fonte
Eu esta solução um pouco. Achei que pode ser útil definir str = "" .__ class__, que agora permite que isinstance (object, str) seja gravado normalmente e também garante que str (object) retorne uma string unicode no Python 2 e no Python 3.
Amicitas
Isso não funciona ao analisar XML: some_element.texté um 'str', mas a comparação com 'unicode' falharia
vault
Não funciona com string unicode no python 2: isinstance (u'XXX ',' '.__ class__) == False
Fil
0

Você pode tentar isso no início do seu 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

e mais tarde no código:

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

Seja cuidadoso! No python 2, stre bytessão essencialmente os mesmos. Isso pode causar um erro se você estiver tentando distinguir entre os dois.

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

tipo (string) == str

retorna true se for uma string e false se não

confused_programmer241
fonte
1
Não é verdade para Python 2, onde stringé uma string unicode
lxop