我的代码需要str
,但会处理以下列方式传递bytes
的情况:
if isinstance(data, bytes):
data = data.decode()
不幸的是,这在bytearray
的情况下不起作用。是否有更通用的方法来测试对象是bytes
还是bytearray
,还是应该检查两者? hasattr('decode')
和我一样糟糕吗?
答案 0 :(得分:42)
您可以在这里使用一些方法。
由于Python是duck typed,您可以按照以下方式执行操作(这似乎是通常建议的方式):
try:
data = data.decode()
except AttributeError:
pass
然而,您可以使用hasattr
来描述它,它可能会很好。当然,这是假设给定对象的.decode()
方法返回一个字符串,并且没有令人讨厌的副作用。
我个人建议使用例外或hasattr
方法,但无论你使用什么,都取决于你。
这种方法并不常见,但有可能:
data = str(data, "utf-8")
其他编码是允许的,就像缓冲协议的.decode()
一样。您还可以传递第三个参数来指定错误处理。
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。
答案 1 :(得分:21)
您可以使用:
isinstance(data, (bytes, bytearray))
由于此处使用了不同的基类。
>>> 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'>
答案 2 :(得分:8)
除非您知道我们不知道的事情,否则此代码不正确:
<?php
\app\assets\TransportAsset::register($this);
?>
<!-- Some HTML Code -->
您(似乎)不知道if isinstance(data, bytes):
data = data.decode()
的编码。你假设it's UTF-8,但这很可能是错的。由于您不知道编码,you do not have text。你有字节,在阳光下可能有任何意义。
好消息是大多数随机字节序列都不是有效的UTF-8,所以当它中断时,它会大声破坏(data
是默认值),而不是默默地做错事。更好的消息是,大多数恰好是有效UTF-8的随机序列也是有效的ASCII,(nearly)每个人都同意如何解析。
坏消息是没有合理的方法来解决这个问题。有一种提供编码信息的标准方法:使用errors='strict'
代替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, ...)
必须是第一个参数。如果这些限制不适合您,请改用其他答案之一。
答案 3 :(得分:3)
这取决于你想要解决的问题。如果您希望使用相同的代码将两种情况转换为字符串,则可以先将类型转换为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)
这样,你的答案可能是:
data = bytes(data).decode()
无论如何,我建议明确地将'utf-8'
写入解码,如果你不关心几个字节。原因是下次您或其他人阅读源代码时,情况会更明显。
答案 4 :(得分:1)
这里有两个问题,答案也不同。
第一个问题,这篇文章的标题是确定一个对象是否是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()。
答案 5 :(得分:1)
>>> content = b"hello"
>>> text = "hello"
>>> type(content)
<class 'bytes'>
>>> type(text)
<class 'str'>
>>> type(text) is str
True
>>> type(content) is bytes
True
答案 6 :(得分:0)
测试if isinstance(data, bytes)
或if type(data) == bytes
等在Python 2中不起作用,其中简单的ASCII字符串通过了测试!因为我同时使用Python 2和Python 3,所以为了克服这一点,我进行了以下检查:
if str(type(data)).find("bytes") != -1: print("It's <bytes>")
这有点难看,但它确实完成了问题提出的任务,并且始终以最简单的方式起作用。