У меня есть код, который ожидает, str
но будет обрабатывать случай передачи bytes
следующим образом:
if isinstance(data, bytes):
data = data.decode()
К сожалению, это не работает в случае bytearray
. Есть ли более общий способ проверить, является ли объект одним bytes
или bytearray
двумя, или я должен просто проверить оба? Так hasattr('decode')
плохо, как я думаю?
python
python-3.x
А. Уилкокс
источник
источник
str
. Другой код должен как можно скорее преобразовывать байты в Unicode при вводе. (2) «подобный байтам» имеет особое значение в Python (объекты, поддерживающие протокол буфера (только C))Ответы:
Здесь вы можете использовать несколько подходов.
Утка печатает
Поскольку Python типизирован как утка , вы можете просто сделать следующее (кажется, обычно предлагается):
try: data = data.decode() except (UnicodeDecodeError, AttributeError): pass
Однако вы можете использовать,
hasattr
как вы описываете, и, вероятно, все будет хорошо. Это, конечно, предполагает, что.decode()
метод для данного объекта возвращает строку и не имеет неприятных побочных эффектов.Я лично рекомендую либо исключение, либо
hasattr
метод, но что бы вы ни использовали, зависит от вас.Используйте str ()
Такой подход необычный, но возможен:
data = str(data, "utf-8")
Допускаются другие кодировки, как и в протоколе буфера
.decode()
. Вы также можете передать третий параметр, чтобы указать обработку ошибок.Универсальные функции с однократной отправкой (Python 3.4+)
Python 3.4 и выше включают изящную функцию, называемую универсальными функциями с однократной отправкой, через functools.singledispatch . Это немного более подробно, но также более ясно:
def func(data): # This is the generic implementation data = data.decode() ... @func.register(str) def _(data): # data will already be a string ...
Вы можете также сделать специальные обработчик
bytearray
иbytes
объекты , если вы так выбрали.Осторожно : функции однократной отправки работают только с первым аргументом! Это намеренная функция, см. PEP 433 .
источник
hasattr
больше, чем попытка / за исключением того, что вы случайно не проглотили какую-то ошибку в функции декодирования, но +1.Ты можешь использовать:
Здесь используется другой базовый класс.
>>> bytes.__base__ <type 'basestring'> >>> bytearray.__base__ <type 'object'>
Проверить
bytes
>>> by = bytes() >>> isinstance(by, basestring) True
Однако,
>>> buf = bytearray() >>> isinstance(buf, basestring) False
Приведенные выше коды тестируются под Python 2.7.
К сожалению, в Python 3.4 они такие же ....
>>> bytes.__base__ <class 'object'> >>> bytearray.__base__ <class 'object'>
источник
>>> content = b"hello" >>> text = "hello" >>> type(content) <class 'bytes'> >>> type(text) <class 'str'> >>> type(text) is str True >>> type(content) is bytes True
источник
type(text) is bytes
будет True!Этот код неверен, если вы не знаете чего-то, чего мы не знаем:
if isinstance(data, bytes): data = data.decode()
Вы (кажется) не знаете кодировку
data
. Вы предполагаете, что это UTF-8 , но это вполне может быть ошибкой. Поскольку вы не знаете кодировку, у вас нет текста . У вас есть байты, которые могут иметь любое значение под солнцем.Хорошая новость заключается в том, что большинство случайных последовательностей байтов недействительны для UTF-8, поэтому, когда он прерывается, он будет громко ломаться (
errors='strict'
по умолчанию) вместо того, чтобы молча делать неправильные вещи. Еще лучшая новость заключается в том, что большинство тех случайных последовательностей, которые оказываются действительными в кодировке UTF-8, также являются действительными ASCII, которые ( почти ) все согласны с тем, как их анализировать.Плохая новость в том, что нет разумного способа исправить это. Существует стандартный способ предоставления информации о кодировке: использовать
str
вместоbytes
. Если какой-то сторонний код передал вам объектbytes
илиbytearray
без какого-либо дополнительного контекста или информации, единственное правильное действие - сбой.Теперь, если вы знаете кодировку, вы можете использовать
functools.singledispatch
здесь:@functools.singledispatch def foo(data, other_arguments, ...): raise TypeError('Unknown type: '+repr(type(data))) @foo.register(str) def _(data, other_arguments, ...): # data is a str @foo.register(bytes) @foo.register(bytearray) def _(data, other_arguments, ...): data = data.decode('encoding') # explicit is better than implicit; don't leave the encoding out for UTF-8 return foo(data, other_arguments, ...)
Это не работает с методами и
data
должно быть первым аргументом. Если эти ограничения не работают для вас, используйте вместо этого один из других ответов.источник
Это зависит от того, что вы хотите решить. Если вы хотите иметь один и тот же код, который преобразует оба случая в строку, вы можете просто
bytes
сначала преобразовать тип , а затем декодировать. Таким образом, это однострочный:#!python3 b1 = b'123456' b2 = bytearray(b'123456') print(type(b1)) print(type(b2)) s1 = bytes(b1).decode('utf-8') s2 = bytes(b2).decode('utf-8') print(s1) print(s2)
Таким образом, ответ для вас может быть таким:
В любом случае, я предлагаю писать
'utf-8'
явно для декодирования, если вы не хотите сэкономить несколько байтов. Причина в том, что в следующий раз, когда вы или кто-то другой прочтете исходный код, ситуация станет более очевидной.источник
Здесь есть два вопроса, и ответы на них разные.
Первый вопрос, название этого поста: как правильно определить, является ли объект байтовым объектом в Python? Это включает в себя ряд встроенных типов (
bytes
,bytearray
,array.array
,memoryview
, другие?) И , возможно , также определяемые пользователем типы. Лучший способ проверить их - это попытаться создатьmemoryview
из них:>>> memoryview(b"foo") <memory at 0x7f7c43a70888> >>> memoryview(u"foo") Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: memoryview: a bytes-like object is required, not 'str'
Однако в тексте исходного сообщения вопрос звучит так, будто вместо этого возникает вопрос: как мне проверить, поддерживает ли объект decode ()? Ответ @ elizabeth-myers на этот вопрос великолепен. Обратите внимание, что не все байтовые объекты поддерживают decode ().
источник
.release()
или использовать версию диспетчера контекста.memoryview
будет немедленно освобождено и.release()
будет вызываться неявно. Но я согласен, что лучше не полагаться на это, поскольку не все реализации Python учитываются по ссылкам.Тест
if isinstance(data, bytes)
orif type(data) == bytes
и т. Д. Не работает в Python 2, где простая строка ASCII проходит проверку! Поскольку я использую как Python 2, так и Python 3, для решения этой проблемы я выполняю следующую проверку:if str(type(data)).find("bytes") != -1: print("It's <bytes>")
Это немного некрасиво, но выполняет работу, которую задает вопрос, и всегда работает самым простым способом.
источник
str
объекты являютсяbytes
хотя:str is bytes
->True
в python2