안녕하세요. IT 엘도라도 에 오신 것을 환영합니다.
글을 쓰는 것은 귀찮지만 다시 찾아보는 것은 더 귀찮습니다.
완전한 나만의 것으로 만들기 위해 지식을 차곡차곡 저장해 보아요.   포스팅 둘러보기 ▼

파이썬 (Python)

[Python] bytes, bytearray, 인코딩 및 디코딩

피그브라더 2020. 7. 9. 22:53

1. bytes, bytearray (바이트 배열 객체) - 왜 필요할까?

파이썬에는 바이트 배열을 나타내는 객체의 타입으로 bytes, bytearray가 존재한다. 즉 1바이트(= 8비트) 크기의 요소들로 이뤄진 리스트를 나타내는 타입인 것이다. 그렇다면 bytes, bytearray 타입의 바이트 배열 객체와 str 타입의 문자열 객체는 어떤 차이가 있을까? 이를 이해하기 위해서는 다음과 같은 절대적인 사실을 떠올릴 필요가 있다. 바로 "컴퓨터는 오로지 바이트 배열만 저장할 수 있다"는 것이다. 즉 컴퓨터에 무언가를 저장하려면 먼저 그것을 바이트 배열의 형태로 '인코딩(Encoding)'을 해야 한다. 다음은 음악 파일, 사진 파일, 문자 파일 등을 컴퓨터에 저장할 수 있는 바이트 배열의 형태로 인코딩을 하는 예시를 나타낸다. 여기서 MP3, WAV, PNG, JPG, ASCII, UTF-8은 모두 인코딩 방식의 한 종류라고 할 수 있다. 

 

  • EX 1) 음악 파일을 저장하고 싶다면 먼저 그것을 MP3, WAV 등의 방식으로 인코딩을 해야 한다. 
  • EX 2) 사진 파일을 저장하고 싶다면 먼저 그것을 PNG, JPG 등의 방식으로 인코딩을 해야 한다. 
  • EX 3) 문자 파일을 저장하고 싶다면 먼저 그것을 ASCII, UTF-8 등의 방식으로 인코딩을 해야 한다.

 

즉 인코딩이란 음악 파일, 사진 파일, 문자 파일 등을 컴퓨터에 저장할 수 있는 바이트 배열의 형태로 표현하기 위한 수단을 의미한다. 파이썬에서 bytes, bytearray 타입의 바이트 배열 객체는 그렇게 인코딩 된 결과에 해당하는 바이트 배열을 나타내기 위한 용도로 사용된다. 뒤에서 더 자세히 알아보겠지만, 문자열 객체를 컴퓨터에 저장하기 위한 바이트 배열 객체로 인코딩하고 이를 다시 디코딩하는 예시를 간단히 살펴보면 다음과 같다.

 

  • b = 'I am a string'.encode('ascii')  # ASCII 방식으로 인코딩 된 바이트 배열 객체를 반환
  • print(b)  # 출력 결과 : b'I am a string' (인간이 읽을 수 있는 형태로 파이썬이 적절히 디코딩하여 보여준 것)
  • b.decode('ascii')  # ASCII 방식으로 디코딩된 문자열 객체를 반환

 

결국 인코딩과 디코딩은 서로 역 연산의 관계이다. 무엇이든지 간에 디스크에 저장되려면 먼저 인코딩이 이뤄져야 하고, 인간에 의해 읽히거나 사용되려면 먼저 디코딩이 이뤄져야 하는 것이다. 알고 보면 단순한 것이니 너무 어렵게 생각하지 말도록 하자.

 

2. bytes 객체의 이해

바이트 배열을 나타내는 객체의 타입으로, 각 요소를 변경할 수 없는 immutable 특성을 지닌다(튜플과 비슷).

 

bytes 객체는 다음과 같은 방법들을 통해 생성할 수 있다.

 

  • b'문자열 내용' : 해당 문자열을 ASCII 방식으로 인코딩한 바이트 배열 객체를 생성
  • bytes(길이) : 정해진 길이만큼의 0x00으로 채워진 바이트 배열 객체를 생성
  • bytes(반복 가능 객체) : 반복 가능한 객체로 바이트 배열 객체를 생성
  • bytes(바이트 배열 객체) : 바이트 배열 객체로 바이트 배열 객체를 생성
b'Hello, world!'  # 문자열로 바이트 배열 객체 생성
# 출력 결과 : b'Hello, world!'

bytes(10)  # 0이 10개 들어있는 바이트 배열 객체 생성 
# 출력 결과 : b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

bytes([10, 20, 30, 40, 50])  # 반복 가능 객체로 바이트 배열 객체 생성 
# 출력 결과 : b'\n\x14\x1e(2'

bytes(b'hello')  # 바이트 배열 객체로 바이트 배열 객체 생성
# 출력 결과 : b'hello'

 

※ 참고로 파이썬이 bytes 객체를 콘솔에 출력해줄 때의 규칙은 다음과 같다.
1. 출력 가능한 형태의 1바이트 ASCII 문자들은 그대로 출력한다.
2. 그렇지 않은 나머지 경우에는 바이트의 값을 16진수의 형태(\x??)로 출력한다.

 

3. bytearray 객체의 이해

바이트 배열을 나타내는 객체의 타입으로, 각 요소를 변경할 수 있는 mutable 특성을 지닌다(리스트와 비슷).

 

bytearray 객체도 마찬가지로 다음과 같은 방법들을 통해 생성할 수 있다.

 

  • bytearray(길이) : 정해진 길이만큼의 0x00으로 채워진 바이트 배열 객체를 생성
  • bytearray(반복 가능 객체) : 반복 가능한 객체로 바이트 배열 객체를 생성
  • bytearray(바이트 배열 객체) : 바이트 배열 객체로 바이트 배열 객체를 생성
bytearray(10)  # 0이 10개 들어있는 바이트 배열 객체 생성 
# 출력 결과 : bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') 

bytearray([10, 20, 30, 40, 50])  # 반복 가능 객체로 바이트 배열 객체 생성 
# 출력 결과 : bytearray(b'\n\x14\x1e(2')

bytearray(b'hello')  # 바이트 배열 객체로 바이트 배열 객체 생성
# 출력 결과 : bytearray(b'hello')

 

bytearray 객체는 bytes 객체와 달리 다음과 같이 각 요소의 값을 변경할 수 있다. 단 요소의 값을 바꿀 때는 항상 정수(int) 값을 할당해야 한다는 것에 주의하자. 문자를 넣고 싶다면 파이썬의 내장 함수 ord()를 활용하여 아스키 코드 값을 넣어주도록 하자.

x = bytearray(b'hello')
x[0] = ord('a')  # ord는 문자의 아스키 코드 값을 반환
x
# 출력 결과 : bytearray(b'aello')

 

4. 인코딩 및 디코딩

# 파이썬의 문자열 인코딩 방식은 기본적으로 UTF-8
s = 'Hello, world!'

# 그러나 b 표현식을 사용하여 바이트 배열 객체를 만들면 ASCII 방식으로 인코딩함
# 만약 ASCII 문자가 아닌 문자가 포함되면 에러가 발생 ("bytes can only contain ASCII literal characters.")
b = b'Hello, world!'

# 문자열 객체를 바이트 배열 객체로 인코딩하는 방법 : encode() 함수
# 인코딩 방식을 지정해주지 않으면 기본적으로 UTF-8 방식을 사용
b1 = s.encode()
b2 = s.encode('utf-8')
b3 = s.encode('euc-kr')
b4 = s.encode('cp949')
b5 = s.encode('ascii')

# 바이트 배열 객체를 문자열 객체로 디코딩하는 방법 : decode() 함수
# 디코딩 방식을 지정해주지 않으면 기본적으로 UTF-8 방식을 사용
s1 = b1.decode()
s2 = b2.decode('utf-8')
s3 = b3.decode('euc-kr')
s4 = b4.decode('cp949')
s5 = b5.decode('ascii')

 

 

 

 

 

 

본 글은 아래 링크의 내용을 참고하여 학습한 내용을 나름대로 정리한 글임을 밝힙니다.

https://stackoverflow.com/questions/6224052/what-is-the-difference-between-a-string-and-a-byte-string

https://dojang.io/mod/page/view.php?id=2462