Jak sprawdzić, czy zmienna jest ciągiem zgodnym z Pythonem 2 i 3

171

Wiem, że mogę używać: isinstance(x, str)w python-3.x, ale muszę sprawdzić, czy coś jest ciągiem znaków również w python-2.x. Będzie isinstance(x, str)działać zgodnie z oczekiwaniami w Pythonie-2.x? A może będę musiał sprawdzić wersję i użyć isinstance(x, basestr)?

W szczególności w pythonie-2.x:

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

a python-3.x nie ma u"foo"

Randall Hunt
źródło
2
u "" składnia literałów Unicode została ponownie wprowadzona w Pythonie 3.3
jfs
Dziwny. Otrzymuję `` `>>> isinstance (u" test ", basestring) True` `` `na Pythonie 2.7.16
Darakian

Odpowiedzi:

209

Jeśli piszesz kod kompatybilny z 2.xi 3.x, prawdopodobnie będziesz chciał użyć sześciu :

from six import string_types
isinstance(s, string_types)
ecatmur
źródło
Przepraszam, jestem trochę zdezorientowany co do następującego wyniku. >>> isinstance(u"foo", string_types) True >>> isinstance(u"foo".encode("utf-8"), string_types) True Spodziewałem się, że isinstance (u "foo", string_types) zwróci false.
Chandler.Huang
1
@ Chandler.Huang to pytanie dotyczy identyfikacji stri unicodePythona 2 lub strPythona 3. Jeśli nie chcesz unicodeliczyć na Python 2, po prostu użyj str.
ecatmur
@ecatmur woops, dzięki! usunął go, więc nikt się nie pomyli
runDOSrun
4
możesz również użyć go z futurepakietu zamiast six:from future.utils import string_types
SuperGeo
113

Najbardziej zwięzłe podejście, które znalazłem bez polegania na pakietach takich jak sześć, to:

try:
  basestring
except NameError:
  basestring = str

to zakładając, że sprawdzałeś ciągi znaków w Pythonie 2 w najbardziej ogólny sposób,

isinstance(s, basestring)

będzie teraz działać również dla Pythona 3+.

hbristow
źródło
10
Py3, basestring = (str, bytes)odrequests/compat.py
Tanky Woo
Fajnie, ale dlaczego? Byłoby miło, gdyby Python3 był tutaj wstecznie kompatybilny. Powyższe rozwiązania działają. Byłoby jeszcze lepiej, gdyby nie było takiej potrzeby.
guettli
2
Aby zadowolić zarówno wsparcie dla py2 i 3, jak i mypy, skończyłem zif not hasattr(__builtins__, "basestring"): basestring = (str, bytes)
Dave Lee
35

A co z tym, działa we wszystkich przypadkach?

isinstance(x, ("".__class__, u"".__class__))
Fil
źródło
@holdenweb: Nie i tak - myślę, że sprytny hack „wpływa tylko tam, gdzie jest potrzebny”.
Dilettant
1
Powodem, dla którego podoba mi się ta odpowiedź, jest to, że jest ona przyjazna przy migracji z pythona2 na 3.
Tiagojdferreira
4
Wybrałem również tę opcję, zawijając ją w funkcję pomocniczą, więc pojawia się tylko raz, aw dokumentacji jest miejsce na przypisanie Fil.
Carl Smith
2
Schludny i sam go używałem, dopóki nie zorientowałem się, że też mam from __future__ import unicode_literalsaktywny. Teraz jadę z:isinstance(val, (str, u"".__class__))
Grahamem Klyne
18

To jest odpowiedź @Lev Levitsky, trochę przepisana.

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

try/ exceptTest odbywa się raz, a następnie definiuje funkcję, która zawsze działa i jest tak szybko, jak to możliwe.

EDYCJA: Właściwie nie musimy nawet dzwonić isinstance(); musimy tylko ocenić basestringi sprawdzić, czy otrzymamy NameError:

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

Myślę jednak, że łatwiej jest podążać za wezwaniem isinstance().

steveha
źródło
isinstance("", basestring)to właśnie miałem na myśli mówiąc „dzwonienie”. W każdym razie +1.
Lev Levitsky,
1
Python jest bardzo dynamicznym językiem i nie sądzę, żeby taki test wyglądał źle. Jest to przydatna technika, aby raz coś wymyślić i na tej podstawie skonfigurować funkcję, która zawsze będzie poprawna. Dzięki za +1.
steveha
5
Zapisałbym to jako:try: string_types = basestring except NameError: string_types = str
jfs
12

futureBiblioteka dodaje (Python 2) kompatybilnych nazw , więc można kontynuować pisanie Python 3 . Możesz w prosty sposób wykonać następujące czynności:

from builtins import str
isinstance(x, str) 

Aby go zainstalować , po prostu wykonaj pip install future.

Jako zastrzeżenie , to tylko wsparcie python>=2.6, >=3.3ale to jest bardziej niż nowoczesny six, który jest jedynie zalecana w przypadku korzystaniapython 2.5

toto_tico
źródło
8

Może użyj obejścia takiego jak

def isstr(s):
    try:
        return isinstance(s, basestring)
    except NameError:
        return isinstance(s, str)
Lev Levitsky
źródło
Przepraszam, że zawracam ci głowę, ale isinstance(u'hello', basestr)daje SyntaxError: invalid syntaxmi to w Pythonie 3.2.3 pod Window 7 .. masz pojęcie, dlaczego tak się dzieje? Wygląda na to, że nie podoba mi się u- dostaję ten błąd z stribasestr
Levon,
1
@Levon Żaden problem :) To dlatego, że Python3 nie ma takiej składni , ponieważ strw Pythonie3 jest z definicji Unicode. W związku z tym nie ma basestringtypu, stąd NameErrorto jest złapane w moim fragmencie.
Lev Levitsky,
Ma teraz tę składnię jak noop. w 3.3
Randall Hunt
2
Sugerowałbym wykonanie try/ excepttest jeden raz i na podstawie wyników tego pojedynczego testu isstr()poprawnie zdefiniujesz . Nie ma potrzeby ponoszenia narzutu w postaci wyjątku dla każdego wywołaniaisstr() .
steveha
@Ranman ma rację co do Pythona 3.3, tutaj jest link do PEP .
Lev Levitsky
7

Możesz pobrać klasę obiektu, wywołując object.__class__, więc aby sprawdzić, czy obiekt jest domyślnym typem ciągu:

    isinstance(object,"".__class__)

I możesz umieścić następujący kod na górze swojego kodu, aby ciągi w cudzysłowach były w formacie Unicode w Pythonie 2:

    from __future__ import unicode_literals
Martin Hansen
źródło
Mam to rozwiązanie całkiem sporo. Zauważyłem, że przydatne może być zdefiniowanie str = "" .__ class__, co pozwala teraz na normalne zapisywanie isinstance (obiekt, str), a także zapewnia, że ​​str (obiekt) zwróci ciąg znaków Unicode zarówno w Pythonie 2, jak i Pythonie 3.
amicitas
To nie działa podczas analizowania XML: some_element.textjest „str”, ale porównanie z „unicode” nie powiedzie się
przechowalnia
Nie działa z ciągiem znaków Unicode w Pythonie 2: isinstance (u'XXX ', `` .__ class__) == False
Fil
0

Możesz spróbować tego na początku swojego kodu:

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

a później w kodzie:

anystring = "test"
# anystring = 1
if isinstance(anystring, basstring):
    print("This is a string")
else:
    print("No string")
bunkus
źródło
0

Bądź ostrożny! W Pythonie 2 stri bytessą zasadniczo takie same. Może to spowodować błąd, jeśli próbujesz je rozróżnić.

>>> size = 5    
>>> byte_arr = bytes(size)
>>> isinstance(byte_arr, bytes)
True
>>> isinstance(byte_arr, str)
True
Fardin
źródło
-4

type (string) == str

zwraca prawdę, jeśli jest to ciąg znaków, a fałsz, jeśli nie

confused_programmer241
źródło
1
Nie dotyczy Pythona 2, gdzie stringjest ciąg znaków Unicode
lxop