a = b'h\x65llo'
print(list(a))
[104, 101, 108, 108, 111]
print(a)
b'hello'
a = 'a\u0300 propos'
print(list(a))
['a', '̀', ' ', 'p', 'r', 'o', 'p', 'o', 's']
print(a)
à propos
파이썬 프로그램을 작성할 떄 유니코드 데이터를 인코딩하거나 디코딩하는 부분을 인터페이스의 가장 먼 경계 지점에 위치시켜라.
이런 방식을 유니코드 샌드위치 라고 부른다.
str을 사용하자
def to_str(bytes_or_str):
if isinstance(bytes_or_str, bytes):
value = bytes_or_str.decode('utf-8')
else:
value = bytes_or_str
return value # str 인스턴스
print(repr(to_str(b'foo')))
'foo'
print(repr(to_str('bar')))
'bar'
print(repr(to_str(b'\xed\x95\x9c')))
'한'
def to_bytes(bytes_or_str):
if isinstance(bytes_or_str, str):
value = bytes_or_str.encode('utf-8')
else:
value = bytes_or_str
return value # bytes 인스턴스
print(repr(to_bytes(b'foo')))
b'foo'
print(repr(to_bytes('bar')))
b'bar'
print(repr(to_bytes('한글')))
b'\xed\x95\x9c\xea\xb8\x80'
print(b'one' + b'two')
b'onetwo'
print('one' + 'two')
onetwo
print(b'one' + 'two')
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-21-7e91d857e3d1> in <module> ----> 1 print(b'one' + 'two') TypeError: can't concat str to bytes
같은 문자를 갖는 bytes와 str 인스턴스가 같은지 비교하면 False
print(b'foo' == 'foo')
False
print(b'red %s' % b'blue')
b'red blue'
print('red %s' % 'blue')
red blue
하지만 파이썬이 어떤 이진 텍스트 인코딩을 사용할지 알 수 없으므로 str 인스턴스를 bytes 형식화 문자열에 넘길 수는 없음
print(b'red %s' % 'blue')
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-25-996799a8aced> in <module> ----> 1 print(b'red %s' % 'blue') TypeError: %b requires a bytes-like object, or an object that implements __bytes__, not 'str'
하지만 반대는 가능하다.
print('red %s' % b'blue')
red b'blue'
여기서는 bytes 인스턴스의 repr 메서드를 호출함
with open('data.bin', 'w') as f:
f.write(b'\xf1\xf2\xf3\xf4\xf5')
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-27-e42a59df12fe> in <module> 1 with open('data.bin', 'w') as f: ----> 2 f.write(b'\xf1\xf2\xf3\xf4\xf5') TypeError: write() argument must be str, not bytes
'wb'가 아닌 'w'로 열었기 때문임
with open('data.bin', 'wb') as f:
f.write(b'\xf1\xf2\xf3\xf4\xf5')
반대로 읽을 때도 비슷한 오류 발생
with open('data.bin', 'r') as f:
data = f.read()
--------------------------------------------------------------------------- UnicodeDecodeError Traceback (most recent call last) <ipython-input-29-e61b03babdec> in <module> 1 with open('data.bin', 'r') as f: ----> 2 data = f.read() /usr/lib/python3.8/codecs.py in decode(self, input, final) 320 # decode input (taking the buffer into account) 321 data = self.buffer + input --> 322 (result, consumed) = self._buffer_decode(data, self.errors, final) 323 # keep undecoded input until the next call 324 self.buffer = data[consumed:] UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf1 in position 0: invalid continuation byte
with open('data.bin', 'rb') as f:
data = f.read()
data
b'\xf1\xf2\xf3\xf4\xf5'
with open('data.bin', 'r', encoding='cp1252') as f:
data = f.read()
data
'ñòóôõ'
-> python2 이야기인듯 하다.
대부분 시스템 디폴트 인코딩은 utf-8 인데 이는 위 이진 데이터를 읽을 수 없음
따라서 디폴트 인코딩이 다를 수 있으므로 명시해주는게 좋음
import locale
print(locale.getpreferredencoding())
UTF-8