Jak dowiedzieć się, czy obiekt Python jest łańcuchem?


402

Jak mogę sprawdzić, czy obiekt Python jest łańcuchem (zwykłym lub Unicode)?


18
Jason ma na myśli pisanie kaczek (jeśli kwacze jak kaczka, prawdopodobnie jest to kaczka). W Pythonie często „pozwalasz swojemu kodowi na działanie” na dowolny obiekt podobny do łańcucha, bez sprawdzania, czy jest to łańcuch, czy podklasa łańcucha. Aby uzyskać więcej informacji, zobacz: docs.python.org/glossary.html#term-duck-typing
Ben Hoyt

4
To właśnie kocham w SO. Zwykle zadaję pytanie, na które nie ma odpowiedzi, ludzie mówią mi, że i tak nie powinienem i dlaczego, i rozwijam się jako programista. =)
physicsmichael

24
+1: To, że odpowiedź jest rzadko potrzebna, nie oznacza, że ​​pytanie jest nieprawidłowe. Chociaż uważam, że wspaniale jest zachować tutaj ostrożność, nie sądzę, aby warto było zdusić to pytanie.
Trevor

17
Jest to prawdopodobnie najbardziej uzasadnione użycie sprawdzania typu w Pythonie. Ciągi znaków są iterowalne, więc odróżnianie ich od list w inny sposób jest złym pomysłem.
ojrac

3
Zdecydowanie istnieją przypadki, w których konieczne jest odróżnienie ciągów znaków od innych iteracji. Na przykład zobacz kod źródłowy PrettyPrinter w module pprint.
saxman01

Odpowiedzi:



178

Python 2

Aby sprawdzić, czy obiekt ojest typem ciągu podklasy typu ciągu:

isinstance(o, basestring)

ponieważ oba stri unicodesą podklasy basestring.

Aby sprawdzić, czy typ ojest dokładnie str:

type(o) is str

Aby sprawdzić, czy ojest instancją strlub jakąkolwiek podklasą str:

isinstance(o, str)

Powyższe działa również dla ciągów Unicode, jeśli zastąpisz strje unicode.

Jednak może nie być wcale konieczne wykonywanie jawnego sprawdzania typu. „Pisanie kaczką” może pasować do twoich potrzeb. Zobacz http://docs.python.org/glossary.html#term-duck-typing .

Zobacz także Jaki jest kanoniczny sposób sprawdzania typu w python?


zmienna lokalna „str”, do której odniesiono się przed przypisaniem
John KTejik,

@johnktejik python3 vs python2. Musisz sprawdzić basestringw py2.
erikbwork

170

Python 3

W Pythonie 3.x basestringnie jest już dostępny, podobnie jak strjedyny typ ciągu (z semantyką Pythona 2.x unicode).

Zatem sprawdzenie w Pythonie 3.x to po prostu:

isinstance(obj_to_test, str)

Jest to zgodne z poprawką oficjalnego 2to3narzędzia konwersji: konwersja basestringdo str.


94

Python 2 i 3

(kompatybilny)

Jeśli chcesz sprawdzić bez względu na wersję Pythona (2.x vs. 3.x), użyj six( PyPI ) i jego string_typesatrybutu:

import six

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

Wewnątrz six(bardzo lekki moduł z jednym plikiem) po prostu robi to :

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

if PY3:
    string_types = str
else:
    string_types = basestring

Alternatywnie możesz użyć future( PyPI ), aby nawet zachować nazwę:from past.builtins import basestring
David Nemeskey

1
BTW ściągawka to świetne źródło informacji na temat kompatybilności wersji Pythona.
David Nemeskey

1
Co z nieużywaniem żadnego importu? Najpierw spróbuj, basestringa potem wróć do str. Np.def is_string(obj): try: return isinstance(obj, basestring) # python 2 except NameError: return isinstance(obj, str) # python 3
isaacbernat

19

Znalazłem to i więcej pythonic:

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

ponieważ są obiekty typu singleton, to można wykorzystać, aby wykonać porównanie obiektu do rodzaju str


4
Nie jest to ogólnie zalecany sposób testowania typu, z powodu dziedziczenia: isinstance(obj_to_test, str)jest oczywiście przeznaczony do testowania typu, i ma tę zaletę, że stosuje tę samą procedurę, co w przypadku innych przypadków innych niż str.
Eric O Lebigot,

14

Jeśli ktoś chce się trzymać z dala od wyraźnego typu sprawdzania (i tam dobre powody, aby trzymać z dala od niego), prawdopodobnie najbezpieczniejsze części protokołu strun do wyboru jest:

str(maybe_string) == maybe_string

Nie będzie iterować przez iterowalny lub iterator, nie nazywa listy ciągów ciągiem i poprawnie wykrywa ciąg podobny do łańcucha.

Oczywiście są wady. Na przykład str(maybe_string)może być ciężka kalkulacja. Jak często odpowiedź brzmi: to zależy .

EDYCJA: Jak wskazuje @Tcll w komentarzach, pytanie faktycznie dotyczy sposobu wykrywania zarówno ciągów znaków Unicode, jak i bajtowania. W Pythonie 2 ta odpowiedź nie powiedzie się, z wyjątkiem ciągów znaków Unicode zawierających znaki inne niż ASCII, a w Pythonie 3 wróci do wszystkich bajtów.False


W przypadku obiektów, które inicjują się z danymi reprezentacji, może to nie działać zgodnie z oczekiwaniami ... b = b'test'; r = str(b) == bgdzie bprzechowuje takie same dane jak, str(b)ale (będąc obiektem bajtów) nie sprawdza się jako ciąg.
Tcll,

@ Tcll Tak, pytanie faktycznie brzmi „albo zwykły albo Unicode”. Chyba nie przeczytałem go poprawnie.
clacke

11

Aby sprawdzić, czy twoja zmienna jest czymś, co możesz zrobić:

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

Wynik isistance da ci logiczną wartość True lub False, dzięki czemu będziesz mógł odpowiednio dostosować. Możesz sprawdzić oczekiwany akronim swojej wartości, początkowo używając: type (s) Zwróci to napis „str”, dzięki czemu możesz go użyć w funkcji isistance.


5

Mogę sobie z tym poradzić w stylu pisania kaczego, jak wspominają inni. Skąd mam wiedzieć, że ciąg jest naprawdę ciągiem? Cóż, oczywiście poprzez konwersję na ciąg!

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

Jeśli argument jest już ciągiem lub typem Unicode, słowo real_word zachowa swoją wartość bez modyfikacji. Jeśli przekazany obiekt implementuje __unicode__metodę, która jest używana do uzyskania jego reprezentacji Unicode. Jeśli przekazany obiekt nie może być użyty jako ciąg znaków, unicodewbudowane polecenie generuje wyjątek.


3
isinstance(your_object, basestring)

będzie Prawda, jeśli Twój obiekt jest rzeczywiście ciągiem znaków. „str” to słowo zastrzeżone.

przepraszam, poprawną odpowiedzią jest użycie „łańcucha bazowego” zamiast „str”, aby zawierał także łańcuchy Unicode - jak zauważono powyżej przez jednego z pozostałych respondentów.


Nie działa w przypadku obiektów Unicode, o które wyraźnie pytano w pytaniu.
dbn

1

Tego wieczoru wpadłem na sytuację, w której myślałem, że będę musiał sprawdzić przedstr typ, ale okazało się, że nie.

Moje podejście do rozwiązania problemu będzie prawdopodobnie działało w wielu sytuacjach, dlatego oferuję je poniżej, na wypadek, gdyby inni czytający to pytanie byli zainteresowani (tylko Python 3).

# 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

Niektóre testy:

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

1

To proste, użyj następującego kodu (zakładamy, że wspomniany obiekt to obj) -

if type(obj) == str:
    print('It is a string')
else:
    print('It is not a string.')

0

Możesz to przetestować, łącząc pusty ciąg:

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

Edytuj :

Poprawiam moją odpowiedź po komentarzach wskazujących, że nie udaje się to z listami

def is_string(s):
  return isinstance(s, basestring)

Masz rację, dziękuję za zwrócenie uwagi. Udzieliłem alternatywnej odpowiedzi.
georgepsarakis

-3

Aby uzyskać dobre podejście do pisania w stylu „kaczych znaków”, które ma tę zaletę, że współpracuje zarówno z Pythonem 2.x, jak i 3.x:

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

mądry był blisko pisania kaczką, zanim przeszedł na isinstancepodejście, z wyjątkiem tego, że +=ma inne znaczenie dla list niż +ma.


2
Cóż, masz dwie opinie negatywne i nikt nie skomentował. Nie przegłosowałem, ale nie podoba mi się twoje rozwiązanie, ponieważ: * Zbyt gadatliwy. Aby to zrobić, nie trzeba definiować funkcji. * Kosztowny. Łapanie wyjątków nie jest dobre dla wydajności. * Podatne na błędy. Inny obiekt może zaimplementować add , zobaczyć ciąg znaków i wygenerować inny typ wyjątku, który nie jest TypeError.
Santiagobasulto

Również tutaj stosujesz podejście kaczego pisania, które jest piękne, ale kończy się rzucaniem i łapaniem wyjątku, aby dowiedzieć się czegoś, co nie jest piękne.
Alexey Tigarev

Może to być uzasadniony jedyny pewny sposób na rozróżnienie między łańcuchem podobnym do łańcucha znaków i innymi iterowalnymi ciągami łańcucha. Można szukać takich atrybutów isalpha, ale kto wie, jakich metod można by bezpiecznie szukać?
clacke

I sobie sprawę , że __str__metoda oraz równość może faktycznie być jeden idiotoodporny. Ale nawet to nie jest bez zastrzeżeń.
clacke

@santiagobasulto wyjątki są tanie w Pythonie. Jeśli spodziewasz się błędu 1% czasu, trymoże być szybszy. Jeśli oczekujesz, że 99% czasu, może nie. Różnica w wydajności jest minimalna, lepiej być idiomatycznym, chyba że profilujesz swój kod i nie identyfikujesz go jako wolnego.
Nick T

-4
if type(varA) == str or type(varB) == str:
    print 'string involved'

z EDX - kurs online MITx: 6.00.1x Wprowadzenie do informatyki i programowania za pomocą Pythona


6
Jest to prawdopodobnie najgorszy możliwy sposób sprawdzenia. Nie tylko wyklucza obiekty Unicode, ale nawet wyklucza podklasy str!
sierpień
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.