Как проверить, является ли переменная строкой с Python 2 и 3 совместимостью


171

Я знаю, что могу использовать: isinstance(x, str)в python-3.x, но мне нужно проверить, является ли что-то строкой в ​​python-2.x. Будет ли isinstance(x, str)работать должным образом в Python-2.x? Или мне нужно будет проверить версию и использовать isinstance(x, basestr)?

В частности, в python-2.x:

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

и python-3.x не имеет u"foo"


2
u "" синтаксис для литералов Unicode вновь введен в Python 3.3
jfs

Странный. Я получаю `` `>>> isinstance (u" test ", basestring) True` `` на Python 2.7.16
Darakian

Ответы:


209

Если вы пишете 2.x-and-3.x-совместимый код, вы, вероятно, захотите использовать шесть :

from six import string_types
isinstance(s, string_types)

Извините, я немного запутался в следующем результате. >>> isinstance(u"foo", string_types) True >>> isinstance(u"foo".encode("utf-8"), string_types) True Я ожидал, что isinstance (u "foo", string_types) вернет false.
Chandler.Huang

1
@ Chandler.Huang этот вопрос касается идентификации strи unicodeна Python 2, или strна Python 3. Если вы не хотите unicodeрассчитывать на Python 2, просто используйте str.
Ecatmur

@ecatmur woops, спасибо! удалил его, чтобы никто не запутался
запустите DOSrun

4
Вы также можете использовать его из futureпакета вместо six:from future.utils import string_types
SuperGeo

113

Самый краткий подход, который я нашел, не полагаясь на пакеты типа шести, это:

try:
  basestring
except NameError:
  basestring = str

затем, при условии, что вы проверяли строки в Python 2 самым общим способом,

isinstance(s, basestring)

теперь также будет работать для Python 3+.


10
Для py3, basestring = (str, bytes)изrequests/compat.py
Tanky Woo

Хорошо, но почему? Было бы хорошо, если бы Python3 был обратно-совместимым здесь. Над решениями работает. Было бы еще лучше, если бы в этом не было необходимости.
Геттли

2
Чтобы удовлетворить как py2 & 3 поддержку, так и mypy, я закончил сif not hasattr(__builtins__, "basestring"): basestring = (str, bytes)
Dave Lee

35

Как насчет этого, работает во всех случаях?

isinstance(x, ("".__class__, u"".__class__))

@holdenweb: Нет и да - изящный взлом "только удары, где необходимо", я думаю.
Дилетант

1
Причина, по которой мне нравится этот ответ, заключается в том, что он удобен при переходе с python2 на 3.
Tiagojdferreira

4
Я также выбрал эту опцию, заключив ее в вспомогательную функцию, чтобы она появлялась только один раз, и в строке документации есть место для ссылки на Fil.
Карл Смит

2
Аккуратно, и я использовал его сам, пока не понял, что у меня тоже есть from __future__ import unicode_literalsактивный. Теперь я собираюсь с:isinstance(val, (str, u"".__class__))
Грэм Клин

18

Это ответ @Lev Левицкого, переписанный немного.

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

try/ exceptТест выполняется один раз, а затем определяет функцию , которая всегда работает и как можно быстрее.

РЕДАКТИРОВАТЬ: На самом деле, нам даже не нужно звонить isinstance(); нам просто нужно оценить basestringи посмотреть, получим ли мы NameError:

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

Я думаю, что легче последовать призыву isinstance(), хотя.


isinstance("", basestring)это то, что я имел в виду под «звонить». В любом случае +1.
Лев Левицкий

1
Python - это очень динамичный язык, и я не думаю, что такое тестирование выглядит плохо. Это полезный метод для выяснения чего-то один раз и на этом основании настройки функции, которая всегда будет правильной. Спасибо за +1.
Steveha

5
Я написал бы это как:try: string_types = basestring except NameError: string_types = str
JFS

12

futureБиблиотека добавляет (в Python 2) совместимые имена , так что вы можете продолжать писать Python 3 . Вы можете просто сделать следующее:

from builtins import str
isinstance(x, str) 

Чтобы установить его , просто выполните pip install future.

В качестве предостережения , он только поддерживает python>=2.6, >=3.3но он более современный, чем six, который рекомендуется только при использованииpython 2.5


8

Может быть, использовать обходной путь, как

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

Извините, что беспокою вас, но isinstance(u'hello', basestr)уступает SyntaxError: invalid syntaxмне с Python 3.2.3 под Windows 7 ... есть идеи, почему это будет? Кажется, это не нравится u- я получаю эту ошибку strиbasestr
Левон

1
@Levon Нет проблем :) Это потому, что Python3 не имеет такой синтаксис , как strв Python3 по определению Unicode. Соответственно, нет basestringтипа, следовательно, то, NameErrorчто поймано в моем фрагменте.
Лев Левицкий

Теперь он имеет такой синтаксис как noop. в 3.3
Рэндалл Хант

2
Я бы посоветовал сделать try/ excepttest один раз, и, основываясь на результатах этого теста, вы определите isstr()правильно. Нет необходимости накладывать накладные расходы на исключение для каждого вызова isstr().
Steveha

@Ranman прав насчет Python 3.3, вот ссылка на PEP .
Лев Левицкий

7

Вы можете получить класс объекта, вызвав его object.__class__, чтобы проверить, является ли объект строковым типом по умолчанию:

    isinstance(object,"".__class__)

И Вы можете поместить следующее в верхней части своего кода, чтобы строки, заключенные в кавычки, были в юникоде в python 2:

    from __future__ import unicode_literals

Я этого решения совсем немного. Я обнаружил, что может быть полезно определить str = "" .__ class__, который теперь позволяет нормально писать isinstance (object, str), а также гарантирует, что str (object) будет возвращать строку Unicode как в Python 2, так и в Python 3.
amicitas

Это не работает при разборе XML: some_element.textэто 'str', но сравнение с 'unicode' не удастся
хранилище

Не работает со строкой Unicode на Python 2: isinstance (u'XXX ',' '.__ class__) == False
Fil

0

Вы можете попробовать это в начале вашего кода:

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

и позже в коде:

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

0

Быть осторожен! В питоне 2 strи bytesпо сути то же самое. Это может вызвать ошибку, если вы пытаетесь различить их.

>>> size = 5    
>>> byte_arr = bytes(size)
>>> isinstance(byte_arr, bytes)
True
>>> isinstance(byte_arr, str)
True

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.