String czy bytes? encode(), albo decode() – oto jest pytanie.

Podczas automatyzowania testów korzystamy z różnych danych wejściowych, plików czy bibliotek. Ich tekstową informacjami zwrotną (w Python 3) może być typu string lub bytes. Wpływa to na prezentację tych danych i to, w jaki sposób możemy z nich korzystać. Jak można się domyślić możemy przerobić string na bytes i bytes na string, ale może to nieść za sobą nieoczekiwane efekty.

encode decode

String czy bytes? encode(), albo decode() - oto jest pytanie.


Podczas automatyzowania testów korzystamy z różnych danych wejściowych, plików czy bibliotek. Ich tekstową informacją zwrotną (w Python 3) może być ciąg znaków typu string lub bytes. Wpływa to na prezentację tych danych i to, w jaki sposób możemy z nich korzystać. Jak można się domyślić możemy przerobić string na bytes i bytes na string, ale może to nieść za sobą nieoczekiwane efekty.

String vs Bytes

Żeby nie  przedłużać, string w Python 3 jest tworem abstrakcyjnym zapisanym w Unicode’zie i zapiszemy go ‚text’. Za to bytes jest wartością rzeczywistą składających się z wyłącznie ze znaków ASCII, są to zera i jedynki – upraszczając bity – zapisujemy go b’text’.

 >> print(b'text')
b'text'
>> print('text')
text

Problemy zaczynają się, gdy chcemy połączyć ze sobą te dwa ciągi:

>> print('string' + b'bytes')
>> print('string', b'bytes')
string b'bytes'

Jak już wcześniej wspomniałem, bytes składa się  jedynie ze znaków ASCII. A co jeżeli będziemy chcieli dodać np. polski znak diakrytyczny (spoza ASCII)?

>> print(b'ł')

W najprostszym przykładzie, podanym powyżej w informacji zwrotnej otrzymamy wyjątek: „SyntaxError: bytes can only contain ASCII literal characters.”

.format()

Podczas używania formatek (funkcji format) na tekstach także musimy pamiętać jakiego typu jest formatowany tekst. Pamiętaj, że typ bytes nie zawiera w ogóle tej metody:

 >> print(b'bytes {}'.format('add'))
AttributeError: 'bytes' object has no attribute 'format'

Za to formatowanie string’a w Python 3 można powiedzieć, że „łyknie” wszystko, choć niekoniecznie będzie zgodne z naszymi oczekiwaniami.

 >> print("123 {}".format("123"))
123 123
>> print("abc {}".format(b"abc"))
abc b'abc'

Jak widzimy w drugim print’cie dodana formatka pokazuje b’abc’, co ciekawe, Python 3 sam zadbał o to by, stała się ona automatycznie string’iem. Co daje nam nie zbyt oczekiwany tekst abc b’abc’, jako jeden ciąg znaków. Może to być przydatna funkcjonalność, ale osobiście omijałbym ją z daleka, jeśli nie robimy jej całkowicie świadomie.

encode() and decode()

Aby zmienić typ z string na bytes, możesz użyć funkcji encode(). W odwrotną stronę decode(). Funkcje te są przeznaczone wyłącznie do kodowania i dekodowania odpowiednio wcześniej opisanych typów danych. Reasumując string nie zawiera funkcji decode(), a bytes funkcji encode().

 >> print('abc'.encode())
b'abc'
>> print(b'bcd'.decode())
bcd

Należy jednak uważać na encode’owanie tekstów zawierających inne znaki niż ASCII. Może się to skończyć trudnymi do debugowania błędami:

 >> print('abcł'.encode())
b'abc\xc5\x82'

Python 3, choć wprowadza wiele zabezpieczeń, to jak widzimy w powyższych przykładach, nie zwalnia nas od myślenia. Podczas przechodzenia między tymi typami lub ich łączenia, musimy pamiętać, aby nie wpaść w pułapkę własnej niewiedzy bądź nieuwagi, z jakimi danymi aktualnie mamy do czynienia. 

close

Newsletter