[python] 파이썬에서 객체가 바이트와 같은 객체인지 결정하는 적절한 방법은 무엇입니까?

예상 str하지만 bytes다음과 같은 방식 으로 전달되는 경우를 처리하는 코드 가 있습니다 .

if isinstance(data, bytes):
    data = data.decode()

안타깝게도 bytearray. 객체가 bytes또는 인지 여부를 테스트하는보다 일반적인 방법이 bytearray있습니까? 아니면 둘 다 확인해야합니까? 가 hasattr('decode')내가 될 것이라고 느낌으로 나쁜로?



답변

여기에서 사용할 수있는 몇 가지 접근 방식이 있습니다.

오리 타이핑

Python은 duck typed 이므로 다음과 같이 간단하게 수행 할 수 있습니다 (일반적으로 제안되는 방식 인 것 같습니다).

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
    ...

원하는 경우 bytearraybytes개체에 대한 특수 처리기를 만들 수도 있습니다 .

주의 : 단일 디스패치 함수는 첫 번째 인수에서만 작동합니다! 이것은 의도적 인 기능 입니다. PEP 433을 참조하십시오 .


답변

당신이 사용할 수있는:

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에서 테스트되었습니다.

불행히도 파이썬 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


답변

이 코드는 우리가 모르는 것을 알지 않는 한 정확하지 않습니다.

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)

이런 식으로 답은 다음과 같습니다.

data = bytes(data).decode()

어쨌든 'utf-8'몇 바이트를 절약하지 않으려면 디코딩에 명시 적 으로 작성하는 것이 좋습니다 . 그 이유는 다음에 당신이나 다른 사람이 소스 코드를 읽을 때 상황이 더 분명해질 것이기 때문입니다.


답변

여기에는 두 가지 질문이 있으며 그에 대한 답변은 다릅니다.

첫 번째 질문 인이 게시물의 제목은 파이썬에서 객체가 바이트와 같은 객체인지 결정하는 적절한 방법무엇입니까?입니다. 이 유형의 내장의 숫자를 포함 ( 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 ()를 지원하는 것은 아닙니다.


답변

test 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>")

약간 못 생겼지 만 질문이 요구 하는 작업을 수행 하고 항상 가장 간단한 방법으로 작동합니다.