źródło: https://pl.python.org/forum/index.php?topic=5190.0
Dane tekstowe w Pythonie 2.x (bo z kontekstu rozumiem, że o Pythonie 2.x tu mowa) mogą być reprezentowane na dwa sposoby:
1. Obiekt typu str czyli ciąg bajtów (czyli postać, w jakiej dane występują w plikach na dysku, w komunikacji przez sieć itp.) — np. słowo łódź będzie miało różną postać w zależności od zastosowanego kodowania, np. w kodowaniu windows-1250 będzie to '\xb3\xf3d\x9f' (4 bajty: 0xb3, 0xf3, 0x64, 0x9f [zauważmy, że bajt 0x64, jako kod drukowalnego znaku ze zbioru ASCII — litery d, przedstawiany jest przez pythonową funkcję repr() po prostu jako 'd' a nie w postaci wy-escape-owanej '\x64'), w kodowaniu latin2 będzie to '\xb3\xf3d\xbc' (4 bajty: 0xb3, 0xf3, 0x64, 0xbc), w kodowaniu utf-8 będzie to '\xc5\x82\xc3\xb3d\xc5\xba’ (6 bajtów: 0xc5, 0x82, 0xc3, 0xb3, 0x64, 0xc5, 0xba). Informacja o kodowaniu nie jest zawarta w samych danych — dla komputera jest to po prostu ciąg bajtów (liczb całkowitych od 0 do 255) i tyle (a więc to Ty jako programista musisz wiedzieć, jakiego użyć kodowania do ich interpretacji).
Uwaga: jeżeli w kodzie źródłowym swojego programu umieścisz literał napisu typu str używając znaków spoza ASCII, np. „łódź” (a nie np. „\xc5\x82\xc3\xb3d\xc5\xba”), sposób jego interpretacji przez Pythona zależy od 2 rzeczy: a) jakiego kodowania używa Twój edytor tekstu; b) jakie kodowanie jest zadeklarowane na początku Twojego pliku źródłowego (deklaracja # -*- coding: ... -*-; jej brak oznacza domyślne kodowanie: ascii) — musisz zadbać, aby kodowania a i b były zgodne (inaczej nastanie taki bałagan, że sie nie połapiesz); jeżeli np. oba (a i b) będą utf-8, to literał „łódź” będzie równoznaczny literałowi „\xc5\x82\xc3\xb3d\xc5\xba”.
2. Obiekt typu unicode czyli ciąg znaków (mówiąc ściślej: code pointów czyli abstrakcyjnych wartości liczbowych od 0 do 1114111 odpowiadających wg standardu Unicode poszczególnm znakom) — np. słowo łódź będzie miało zawsze taką samą postać: u’\u0142\xf3d\u017a’ (czyli cztery znaki o kodach [code-pointach]: 0x142, 0xf3, 0x64, 0x17a). Dopóki operujesz obiektami typu unicode, w ogóle nie ma tematu takiego czy innego kodowania.
Uwaga: jeżeli w kodzie źródłowym swojego programu umieścisz literał napisu typu unicode używając znaków spoza ASCII, np. u”łódź”, sposób jego interpretacji przez Pythona jest jednoznaczny (literał u”łódź” jest równoznaczny literałowi u”\u0142\xf3d\u017a”), pod warunkiem że kodowanie używane przez Twój edytor tekstu jest zgodne z kodowaniem zadaklarowanym na początku Twojego pliku źródłowego (deklaracją # -*- coding: ... -*-; jej brak oznacza domyślne kodowanie: ascii).
Zasadniczo w 99% przypadków do danych tekstowych należy używać:
- typu str — tylko na wejściu i na wyjściu Twojego programu (pliki, komunikacja sieciowa itp.);
- typu unicode — wewnątrz całego Twojego programu.
Np. zakładając, że w zmiennej bajty_z_sieci masz wyraz łódź zakodowany utf-8, a w zmiennej bajty_z_pliku — ten sam wyraz zakodowany windows-1250…
>>> bajty_z_sieci '\xc5\x82\xc3\xb3d\xc5\xba' >>> bajty_z_pliku '\xb3\xf3d\x9f' >>> bajty_z_sieci == bajty_z_pliku False
Odkodowujemy [ang. decode] oba napisy z postaci bajtowej (str), z użyciem odpowiednich kodowań, do postaci unicode…
>>> napis_z_sieci = bajty_z_sieci.decode('utf-8')
>>> napis_z_pliku = bajty_z_pliku.decode('windows-1250')
…i jak widzimy, oba zawierają ten sam wyraz:
>>> napis_z_sieci u'\u0142\xf3d\u017a' >>> napis_z_pliku u'\u0142\xf3d\u017a' >>> napis_z_sieci == napis_z_pliku True
Mając napis w postaci unicode możemy wygodnie operować na nim jako na tekście, np.:
>>> napis_wynikowy = napis_z_sieci.upper() >>> napis_wynikowy u'\u0141\xd3D\u0179' >>> print napis_wynikowy ŁÓDŹ
Jeżeli chcemy zapisać dane tekstowe do pliku lub wysłać przez sieć, musimy przekonwertować je z postaci unicode do postaci bajtowej czyli str (czyli zakodować [ang. encode] z użyciem jakiegoś kodowania, np. utf-8):
>>> bajty_wynikowe = napis_wynikowy.encode('utf-8')
Teraz możemy np. zapisać te dane do pliku:
>>> with open('dane-wynikowe.txt', 'w') as f:
... f.write(bajty_wynikowe)
...
PS. [Edit] Oczywiście nie każde kodowanie obejmuje wszystkie możliwe znaki.
Weźmy 2 znaki spoza ASCII: francuską literę è (u'\xe8') i polską literę ę (u'\u0119')…
Np. kodowanie latin1 (znane też jako iso-8859-1) obejmuje è, ale nie ę:
'\xe8′
>>> u’\u0119′.encode(’latin1′)
Traceback (most recent call last):
File „<stdin>”, line 1, in <module>
UnicodeEncodeError: 'latin-1′ codec can’t encode character u’\u0119′ in position 0: ordinal not in range(256)
Z kolei kodowania latin2 (znane też jako iso-8859-2) i windows-1250 obejmują ę, ale nie è:
Traceback (most recent call last):
File „<stdin>”, line 1, in <module>
File „/home/zuo/.virtualenvs/unittest_expander/lib/python2.7/encodings/iso8859_2.py”, line 12, in encode
return codecs.charmap_encode(input,errors,encoding_table)
UnicodeEncodeError: 'charmap’ codec can’t encode character u’\xe8′ in position 0: character maps to <undefined>
>>> u’\u0119′.encode(’latin2′)
'\xea’
Oba wyżej wymienione znaki (i wiele, wiele innych — wszystkie reprezentowalne z użyciem unicode) obejmuje kodowanie utf-8:
'\xc3\xa8′
>>> u’\u0119′.encode(’utf-8′)
'\xc4\x99′
Zaś kodowanie ascii (domyślne w Pythonie 2.x) nie obejmuje żadnego z tychże 2 znaków, bo jego zakres to jedynie 128 znaków będących wspólnym podzbiorem wszystkich wyżej wymienionych kodowań…
Traceback (most recent call last):
File „<stdin>”, line 1, in <module>
UnicodeEncodeError: 'ascii’ codec can’t encode character u’\xe8′ in position 0: ordinal not in range(128)
>>> u’\u0119′.encode(’ascii’)
Traceback (most recent call last):
File „<stdin>”, line 1, in <module>
UnicodeEncodeError: 'ascii’ codec can’t encode character u’\u0119′ in position 0: ordinal not in range(128)