Rozdział 15 · Python i akta

Tekst, bytes i kodowanie UTF-8

Pliki przechowują bajty. Sposób, w jaki bajty są zamieniane na tekst, to kodowanie i nie jest to domyślnie uniwersalne.

Tekst i bytes to różne typy

str_vs_bytes.py
print(type("Python"))     # <class 'str'>
print(type(b"Python"))   # <class 'bytes'>
bytes nie jest „łańcuch znaków bez Unicode”
bytes jest łańcuch znaków liczb całkowitych od 0 do 255 (dane binarne), a nie skróconą wersją łańcuch znaków. Tekst łańcuch znaków (str) oraz dane binarne (bytes) — dwa różne typy o różnym przeznaczeniu.

Kodowanie i dekodowanie

Aby zapisać tekst w pliku, jego reprezentacja łańcuch znaków jest zamieniana na bajty — to jest jest nazywana kodowaniem (encode). Podczas czytania dzieje się odwrotnie — Dekodowanie (decode):

encode_decode.py
text = „Cześć”
b = text.encode("utf-8")
print(b)              # b'\\xd0\\x9f\\xd1\\x80\\xd0\\xb8\\xd0\\xb2\\xd0\\xb5\\xd1\\x82'
print(len(text))      #6 – Sześć postaci
print(len(b))         #12 – dwanaście bajtów!

obratno = b.decode("utf-8")
print(obratno)        #Hello
str: „Cześć”
6 postaci
encode("utf-8")
bytes
12 bajtów
decode("utf-8")
str: „Cześć”
6 postaci
Alfabet cyrylicy w UTF-8 zajmuje więcej bajtów niż znaki — to prawdziwy przykład.
Unicode ≠ UTF-8
Unicode jest systemem, który mapuje kody numeryczne na znaki (który symbol oznacza jaką liczbę). UTF-8 jest tylko jednym ze sposobów zapisu tych liczb w bajtach; istnieją też inne kodowania. W tym kursie zawsze wyraźnie wybieramy UTF-8 jako standard dla plików tekstowych — ale to wybór, nie jedyna opcja.

Gdy format tekstu jest znany wcześniej jako UTF-8 (co prawie zawsze ma miejsce na tym kursie), Wyraźne wskazanie encoding="utf-8" wpływa na zachowanie programu przewidywalny i przenośny – zamiast polegać na domyślnym kodowaniu, co jest determinowane przez ustawienia platformy i środowiska wykonawczego.

Dlaczego kodowanie jest ważne

Debug Lab 7: Plik otwarty bez wskazania encoding
bez_encoding.py
with open("privet.txt", "w") as f:   # bez encoding!
    f.write(„Cześć!”)
# Работает по-разному на разных компьютерах и системах —
# кодировка по умолчанию НЕ гарантированно UTF-8 везде.
Co widać na ekranie

Bez jawnego encoding="utf-8" Python używa kodowania domyślnego, zależnego od platformy i ustawień środowiska — a nie gwarantowanie UTF-8. Plik zapisany na jednym komputerze może być błędnie odczytany na innym, jeśli ich domyślne kodowania się różnią.

Poprawiony kod
s_encoding.py
with open("privet.txt", "w", encoding="utf-8") as f:
    f.write(„Cześć!”)   # kodowanie jest jawne i przewidywalne przez cały czas
Debug Lab 8: UnicodeDecodeError: błędne kodowanie podczas odczytu
nevernaya_kodirovka.py
data = „Cześć”.encode("utf-8")
with open("soobshenie.bin", "wb") as f:
    f.write(data)

# czytane jako tekst w INNYM kodowaniu
with open("soobshenie.bin", "r", encoding="ascii") as f:
    print(f.read())
Traceback (most recent call last):
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd0 in position 0: ordinal not in range(128)
Co widać na ekranie

bajty były kodowane w UTF-8 i odczytywane tak, jakby ASCII, kodowania nie pasowały i nie Python mógł przekształcić tych bajtów z powrotem w poprawne znaki. Rozwiązaniem jest odczytanie pliku w tym samym kodowaniu, w którym został zapisany.

Poprawiony kod
pravilnaya_kodirovka.py
with open("soobshenie.bin", "r", encoding="utf-8") as f:
    print(f.read())   #Hello

Trochę głębiej: parametr errors=

U open() jest parametrem errors ("strict" też domyślnie "replace", "ignore") w przypadkach niezgodności kodu.

errors=„ignore”
errors="ignore" cicho wyrzuca nierozpoznane bajty — może to niezauważalnie spowodować utratę części danych. Nie używaj tego jako sposobu na „usunięcie błędu”
Praktyka: tekst, bytes i UTF-8
interaktywny laptop bezpośrednio w przeglądarce – Python 3.14 przez Pyodide, bez instalacji
Otwórz praktykę →