Z pojawieniem się Pythona 3 typ bytes stał się podstawowym sposobem przechowywania i przetwarzania danych binarnych, oddzielając się od łańcuchów (str). W Pythonie 2 łańcuchy (str) mogły zawierać zarówno tekst, jak i bajty, co często prowadziło do błędów przy przetwarzaniu danych w różnych kodowaniach.
W codziennym programowaniu często spotykamy się z zadaniami przesyłania i przechowywania danych poza kontekstem informacji tekstowych — na przykład praca z plikami, zapytaniami sieciowymi i protokołami wymiany. Wymaga to jawnego, wygodnego i bezpiecznego typu, który wyraźnie oddziela sekwencję bajtów od danych tekstowych.
Typ bytes w Pythonie przechowuje niemodyfikowalną sekwencję bajtów (liczb całkowitych od 0 do 255) i może być tworzony z dosłownego zapisu bajtów (z prefiksem b) lub poprzez jawne rzutowanie typów. Aby zapewnić bezpieczną i przewidywalną interakcję między łańcuchami (str) a bajtami (bytes), używane są metody .encode() i .decode(). Przy pracy z plikami, sieciami i różnymi binarnymi protokołami, bytes — główny wybór.
Przykład kodu:
# Tworzenie obiektu bytes b = b'hello' # Za pomocą dosłownego zapisu b2 = bytes([104, 101, 108, 108, 111]) # Z listy liczb całkowitych # Rzutowanie str <=> bytes text = 'tekst' bin_text = text.encode('utf-8') # str -> bytes back = bin_text.decode('utf-8') # bytes -> str # Przykład z plikiem with open('file.bin', 'rb') as f: data = f.read() # data: bytes
Kluczowe cechy:
Czy można połączyć bytes i str w jedną zmienną?
Nie, łączenie przez + lub f-łańcuchy nie działa: jeśli spróbujesz wykonać b'abc' + 'def', pojawi się TypeError. Należy jawnie rzutować typy.
Czym różni się bytes od bytearray?
bytes — typ niemodyfikowalny, tzn. zawartość nie może być zmieniana po utworzeniu. bytearray — zmienny wariant, wspiera metody zmiany bajtów na miejscu.
b = bytes([1, 2, 3]) # immutable ba = bytearray([1, 2, 3]) # mutable ba[0] = 99 # OK b[0] = 99 # TypeError
Jak poznać, ile bajtów zajmie łańcuch przy konwersji przez encode()?
Liczba bajtów zależy od kodowania. Na przykład, dla 'abc' w utf-8 to 3 bajty, a 'Cześć' — 12. Dopiero po wywołaniu encode() można poznać dokładny rozmiar przez len():
s = 'Cześć' # 6 liter b = s.encode('utf-8') # 12 bajtów print(len(b)) # 12
Programista odczytuje plik w trybie 'rb' (bajtowym) i próbuje od razu przetworzyć go jako łańcuch:
with open('file.txt', 'rb') as f: for line in f: print(line.strip()) # line: bytes
Zalety:
Wady:
Programista przetwarza strumienie bajtów przez decode(), wprowadza kontrolę kodowania:
with open('file.txt', 'rb') as f: for line in f: print(line.decode('utf-8').strip())
Zalety:
Wady: