티스토리 뷰
참고:
BETTER WAY 03 - bytes, str, unicode의 차이점을 알자
BETTER WAY 03 - bytes, str, unicode의 차이점을 알자Item03 - Know the Differences Between bytes, str, and unicode Python3 에서는 bytes와 str 두 가지 타입으로 문자 시퀀스를 나타냄bytes 인스턴스는 로(raw) 8비트 값을 저장
excelsior-cjh.tistory.com
1. Bytes, Str
파이썬에서는 문자열 데이터의 시퀀스를 표현하는 두 가지 타입이 있다. → bytes , str
- bytes 인스턴스는 raw 8비트 값을 저장
- str 인스턴스는 Unicode 문자를 저장함
a = b'h\\x65ll0'
print(list(a))
print(a)
>>>
[104, 101, 108, 108, 111] b'hello'
str 인스턴스에는 유니코드코드 포인트가 들어있다.
a = 'a\\u0300 propos'
print(list(a))
print(a)
>>>
['a', '̀', ' ', 'p', 'r', 'o', 'p', 'o', 's'] à propos
2. cases
- str 인스턴스: 직접 대응하는 이진 인코딩이 없음
- bytes: 직접 대응하는 텍스트 인코딩이 없음
- e.g. 유니코드 데이터 → 이진 데이터 로 변환: str의 encode 메서드 호출(대표적 인코딩 방법은 UTF-8이 있음)
- e.g. 이진 데이터 → 유니 코드 데이터 로 변환: bytes의 decode 메서드 호출
- 시스템 디폴트 인코딩을 받아들일 수 있는데 일반적으로 UTF-8이다. 한 문자를 나타내기 위해 1~4 bytes 사용
유니코드 데이터를 인코딩/디코딩하는 부분을 인터페이스의 가장 먼 경계 지점에 위치시켜야 한다. 해당 방법을 유니코드 샌드위치 라고 부름.
프로그램의 핵심 부분은 유니코드 데이터가 들어있는 str을 사용해야 하고, 문자 인코딩에 대해 가정을 해선 안 됨. 다양한 텍스트 인코딩으로 입력 데이터를 받아들일 수 있고, 출력 텍스트 인코딩은 한 가지로 (UTF-8) 엄격히 제한할 수 있음.
파이썬에서 문자 표현 방법이 2가지이기 때문에 아래 두 가지 상황이 자주 발생함
- UTF-8로 인코딩된 8비트 시퀀스를 그대로 사용하고 싶음
- 특정 인코딩을 지정하지 않은 유니코드 문자열을 사용하고 싶음
두 경우를 변환해주고 입력 값이 원하는 값과 일치하는지 두 가지 도우미 함수가 필요함!
1. bytes나 str 인스턴스를 받아 항상 str 반환 decode
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')))
print(repr(to_str('bar')))
print(repr(to_str(b'\\xed\\x95\\x9c'))) # UTF-8에서 한글은 3바이트임
>>>
'foo' 'bar' '한'
2. bytes나 str 인스턴스를 받아 항상 bytes반환 encode
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')))
print(repr(to_bytes('bar')))
print(repr(to_bytes('한글')))
>>>
b'foo' b'bar' b'\xed\x95\x9c\xea\xb8\x80'
연산자 사용시, 같은 타입끼리만 가능함
print(b'one' + b'two')
print('one' + 'two')
# Wrong
# print(b'one' + 'two')
# print('one' + b'two')
이항 연산자 사용하면 같은 타입끼리 비교 가능
assert b'red' > b'blue'
assert 'red' > 'blue'
# Wrong
# assert b'red' > 'blue'
# assert 'red' > b'blue'
- 참고: assert는 뒤의 조건이 True가 아니면 AssertError를 발생한다. (가정 설정문이라 한다.)
내부에 똑같은 문제들이 들어 있어도 인스턴스가 같은지 비교하면 False 가 나옴
print(b'foo' == 'foo')
>>>
False
% 연산자는 각 타입의 형식화 문자열(format string)에 대해 작동
print(b'red %s' % b'blue')
print('red %s' % 'blue')
>>>
b'red blue' red blue
- 참고: format string"문자열" % 값문자열 의미
%s 문자열 %d 정수 %f 부동소수점 실수 - 이 때 문자열의 어느 위치에 값이 들어가는지를 표시하기 위해 문자열 안에 % 기호로 시작하는 형식지정 문자열(format specification string)을 붙인다. 대표적인 형식지정 문자열은 다음과 같다.
- 문자열 뒤에 % 기호를 붙이고 그 뒤에 다른 값을 붙이면 뒤에 붙은 값이 문자열 안으로 들어간다.
여기서 두 번째 문제점이 발생한다.
첫 번째
파이썬이 어떤 이진 텍스트 인코딩을 사용할지 알 수 없어서 str 인스턴스를 bytes 형식화 문자열에 넘길 수 없음
# wrong
# print(b'red %s' % 'blue')
str 형식화 문자열에 bytes 인스턴스를 넘길 수 있지만, 이 경우에는 예상과 다르게 작동
print('red %s' % b'blue')
>>>
red b’blue’
출력에 b'blue' 가 그대로 남음
두 번째
내장함수 open은 디폴트로 유니코드 문자열을 요구한다.
# Error
with open('data.bin', 'w') as f:
f.write(b'\\xf1\\xf2\\xf3\\xf4\\xf5')
>>>
TypeError: write() argument must be str, not bytes\
원인은 str이어야 하는데, bytes라는 점이고, 'w' 모드로 열었기 때문에 오류가 발생한다. 이는 그냥 텍스트 쓰기 모드(wrtie)이며, 이는 이진 데이터가 들어있는 bytes 인스턴스가 아니라 유니코드 데이터가 들어 있는 str 인스턴스를 요구한다.
'wb' 모드의 경우, 이진 쓰기 모드이므로 파일을 열면 해결할 수 있다.
with open('data.bin', 'wb') as f:
f.write(b'\\xf1\\xf2\\xf3\\xf4\\xf5')
또한, 파일의 데이터를 읽을 때(’r’)도 문제가 발생한다.
with open('data.bin', 'r') as f:
f.write(b'\\xf1\\xf2\\xf3\\xf4\\xf5')
>>>
UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0xf1 in …
이것도 'rb' 모드로 열면 해결된다.
with open('data.bin', 'rb') as f:
f.write(b'\\xf1\\xf2\\xf3\\xf4\\xf5')
또는 쓰기의 경우엔 bytes.encode 이를, 읽기의 경우엔 str.decode 를 적용해서 이진 데이터를 해석할 수 있다.
마지막으로 다른 방법은 open 함수의 encoding 파라미터를 명시하면, 이진 데이터가 실제로 인코딩 돼 있다고 가정한다.
with open('data.bin', 'r', encoding='cp1252') as f:
data = f.read()
assert data == 'ñòóôõ'
예외가 사라졌고, 문자열로 해석해서 기존 이진 데이터를 읽었을 때 반환된 것과 전혀 다름
따라서 시스템 디폴트 인코딩이 어떻게 다른지 이해하기 위해선 항상 검사해야하고, 인코딩에 따라 문자열이 달라진다는 점을 이해해야 한다.
python3 -c 'import locale; print(locale.getpreferredencoding())'
검사해보니 cp949 이 뜬다.
디폴트 인코딩이 의심스러운 경우에 open에 encoding='..' 으로 파라미터를 전달해야한다.
'Skills > Pythons' 카테고리의 다른 글
[Python] 딕셔너리 - defaultdict의 사용 (0) | 2022.12.08 |
---|---|
[Python] dictionary 딕셔너리 - in, KeyError, get, setdefualt 메서드 (0) | 2022.12.07 |
[Python] PEP8 스타일 코딩 (2) | 2022.11.25 |
[Python] 파이썬 버전 확인 (0) | 2022.11.25 |
[Python] List to Array, Array to List (0) | 2022.10.26 |
- Total
- Today
- Yesterday
- NLP
- prompt learning
- 구글드라이브서버연동
- stylegan
- 파이썬
- 도커
- 서버에다운
- 구글드라이브서버다운
- python
- vscode 자동 저장
- Prompt
- 데이터셋다운로드
- 퓨샷러닝
- 도커 컨테이너
- docker
- CNN
- few-shot learning
- style transfer
- 서버구글드라이브연동
- cs231n
- 프롬프트
- 구글드라이브연동
- 파이썬 딕셔너리
- 딥러닝
- clip
- support set
- 파이썬 클래스 계층 구조
- Unsupervised learning
- 구글드라이브다운
- 파이썬 클래스 다형성
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |