在Python中,确定对象是否是类似字节的对象的正确方法是什么?
我的代码需要在Python中,确定对象是否是类似字节的对象的正确方法是什么?,python,python-3.x,Python,Python 3.x,我的代码需要str,但会以以下方式处理传递字节的情况: if isinstance(data, bytes): data = data.decode() 不幸的是,这在bytearray的情况下不起作用。是否有一种更通用的方法来测试对象是字节还是字节,还是我应该检查两者?hasattr('decode')是否像我感觉的那样糟糕?您可以使用: isinstance(data, (bytes, bytearray)) 由于这里使用的基类不同 >>> bytes.__ba
str
,但会以以下方式处理传递字节的情况:
if isinstance(data, bytes):
data = data.decode()
不幸的是,这在bytearray
的情况下不起作用。是否有一种更通用的方法来测试对象是字节
还是字节
,还是我应该检查两者?hasattr('decode')
是否像我感觉的那样糟糕?您可以使用:
isinstance(data, (bytes, bytearray))
由于这里使用的基类不同
>>> bytes.__base__
<type 'basestring'>
>>> bytearray.__base__
<type 'object'>
但是,
>>> buf = bytearray()
>>> isinstance(buf, basestring)
False
以上代码是在Python2.7下测试的
不幸的是,在Python3.4下,它们是相同的
>>> bytes.__base__
<class 'object'>
>>> bytearray.__base__
<class 'object'>
>>字节。\u__
>>>拜蒂雷基地__
这里有几种方法可以使用
鸭子打字
由于Python是,您可以简单地执行以下操作(这似乎是通常建议的方式):
但是,您可以使用您描述的hasattr
,这样可能就可以了。当然,这是假设给定对象的.decode()
方法返回字符串,并且没有令人讨厌的副作用
我个人推荐exception或hasattr
方法,但使用什么取决于您
使用str()
这种方法不常见,但也有可能:
data = str(data, "utf-8")
其他编码是允许的,就像缓冲协议的.decode()
一样。您还可以传递第三个参数来指定错误处理
单一分派通用函数(Python 3.4+)
Python3.4及以上版本包括一个称为单分派通用函数的漂亮特性,通过。这有点冗长,但也更明确:
def func(data):
# This is the generic implementation
data = data.decode()
...
@func.register(str)
def _(data):
# data will already be a string
...
如果您愿意,还可以为bytearray
和bytes
对象创建特殊处理程序
注意:单个分派函数只对第一个参数有效!这是一项有意的功能,请参阅。除非您知道我们不知道的内容,否则此代码不正确:
if isinstance(data, bytes):
data = data.decode()
您(似乎)不知道数据的编码。你是在假设,但那很可能是错误的。由于您不知道编码。你有字节,在太阳底下可能有任何意义
好消息是,大多数随机字节序列都不是有效的UTF-8,因此当UTF-8中断时,它会大声中断(errors='strict'
是默认值),而不是默默地做错误的事情。更好的消息是,大多数碰巧是有效的UTF-8的随机序列也是有效的ASCII码,每个人都同意如何解析
坏消息是没有合理的方法来解决这个问题。提供编码信息有一种标准方法:使用str
而不是字节
。如果某个第三方代码在没有任何上下文或信息的情况下将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
必须是第一个参数。如果这些限制不适用于您,请使用其他答案之一。这取决于您想要解决的问题。如果希望使用相同的代码将两种情况转换为字符串,只需先将类型转换为字节
,然后解码即可。这样,它是一个单行程序:
#!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'
写入解码器。原因是下次您或其他人阅读源代码时,情况会更加明显。这里有两个问题,答案不同
第一个问题,这篇文章的标题,是确定对象是否是Python中类似字节的对象的正确方法是什么?这包括许多内置类型(字节
,字节数组
,数组.数组
,内存视图
,其他?)以及用户定义的类型。我所知道的检查这些内容的最佳方法是尝试从它们中创建一个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'
记忆视图(b“foo”)
>>>记忆视图(u“foo”)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:memoryview:需要类似字节的对象,而不是“str”
不过,在原始帖子的正文中,问题似乎是如何测试对象是否支持decode()@伊丽莎白·迈尔斯(elizabeth myers)对这个问题的上述回答非常好请注意,并非所有类似字节的对象都支持decode()
>>>text=“你好”
>>>类型(内容)
>>>类型(文本)
>>>类型(文本)为str
真的
>>>类型(内容)为字节
真的
在Python 2中,如果isinstance(数据,字节)或
如果type(数据)=字节等,则测试不起作用,在Python 2中,一个简单的ASCII字符串通过测试!由于我同时使用Python 2和Python 3,为了克服这一问题,我进行了以下检查:
if str(type(data)).find("bytes") != -1: print("It's <bytes>")
if str(type(data)).find(“bytes”)!=-1:打印(“它的”)
虽然有点难看,但它确实起到了问题所要求的作用,而且它总是以最简单的方式工作。就个人而言,我和下一个家伙一样喜欢python的duck类型。但是,如果您需要检查输入参数并强制输入不同的类型,那么您就不再是duck类型,而是使代码更难阅读和维护。我在这里的建议(其他人可能不同意)是创建多个函数(处理类型强制并委托给一个基本实现)。(1)除非您需要它以兼容旧式Python 2代码;避免同时接受文本和二进制数据。如果您的函数使用文本,那么它应该只接受str
。其他一些代码应该在输入时尽快从字节转换为Unicode。(2) “就像
>>> 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'
if str(type(data)).find("bytes") != -1: print("It's <bytes>")