bytes와 bytearray: 이진 데이터를 다루는 두 가지 방법

Python의 bytes(불변)와 bytearray(가변) 타입을 비교하고, 인코딩/디코딩, hex 변환, int 변환 등 실전 패턴을 정리합니다.

· 3 min read · PALDYN Team

지난 글에서 문자열 메서드를 살펴봤다. 이번에는 문자열과 비슷하게 생겼지만 완전히 다른 영역인 이진(binary) 데이터 타입을 다룬다. Python에는 이진 시퀀스를 다루는 두 타입이 있다. 불변인 bytes와 가변인 bytearray다.

bytes — 불변 이진 시퀀스

bytes는 0~255 범위의 정수 시퀀스다. 한 번 만들면 내용을 바꿀 수 없다.

b = b"hello"          # 리터럴
b2 = bytes([72, 101, 108, 108, 111])  # int 리스트로 생성
b3 = bytes(5)         # 5바이트짜리 0으로 채운 bytes

b[0]   # 72  (int 반환, 문자열과 다름!)
b[1:4] # b'ell'  (슬라이스는 bytes 반환)

인덱스로 접근하면 int가 나온다는 점이 str과 다르다.

bytearray — 가변 이진 시퀀스

bytearraybytes와 동일한 인터페이스를 갖지만 내용을 바꿀 수 있다.

ba = bytearray(b"hello")
ba[0] = 72      # 'H' = 72 으로 변경
ba.append(33)   # '!' 추가
ba.extend(b" world")
print(bytes(ba))  # b'Hello! world'

list처럼 append, extend, insert, pop 메서드가 있다.

bytes와 bytearray 비교

str ↔ bytes 변환

네트워크나 파일 I/O에서 가장 많이 하는 작업이다.

# str → bytes
s = "안녕, Python!"
b = s.encode("utf-8")   # bytes
b_latin = s.encode("utf-8", errors="replace")  # 변환 불가 문자는 ?

# bytes → str
s2 = b.decode("utf-8")

# 오류 처리 옵션
b.decode("ascii", errors="ignore")   # 변환 불가 바이트 무시
b.decode("ascii", errors="replace")  # ? 로 대체

encode()/decode() 모두 두 번째 인자 errors를 받는다. 기본값은 "strict"(오류 시 예외 발생)다.

인코딩·디코딩 패턴

hex, int 변환

b = b"Hi"
b.hex()               # '4869'
bytes.fromhex("4869") # b'Hi'

# 정수 ↔ bytes
n = (1024).to_bytes(2, "big")   # b'\x04\x00'
m = int.from_bytes(n, "big")    # 1024

# little-endian
(1024).to_bytes(2, "little")    # b'\x00\x04'

언제 무엇을 쓸까

상황선택
파일 읽기·네트워크 수신bytes
이진 버퍼를 조각조각 수정bytearray
dict 키로 사용bytes (해시 가능)
대용량 이진 데이터 제자리 수정bytearray (복사 없이 변경)

bytes는 해시 가능하므로 dict 키나 set 원소로 쓸 수 있다. bytearray는 가변이므로 해시 불가다.

memoryview

bytesbytearray를 복사 없이 슬라이스하려면 memoryview를 쓴다.

data = bytearray(b"Hello, World!")
view = memoryview(data)
view[0:5]  # <memory at ...>
bytes(view[0:5])  # b'Hello'  (복사 없이 참조)

대용량 이진 데이터를 처리할 때 불필요한 복사를 줄일 수 있다.


지난 글: 문자열 메서드: split, join, replace와 친구들

다음 글: None: Python의 ‘없음’을 나타내는 단 하나의 값


읽어주셔서 감사합니다. 😊