Po opublikowaniu poprzedniego artykułu z cyklu “Wtorki z Pythonem” dostałem od jednego z czytelników pytanie, dlaczego tak dziwnie skonstruowałem wywołanie funkcji print()
. Chodziło o zapis print("(%s,%s)" % (self.x, self.y))
. W dzisiejszym artykule wyjaśnię, dlaczego taka konstrukcja była konieczna, oraz jak można ten sam wynik osiągnąć innymi sposobami. Odpowiednie formatowanie zmiennych by wyświetlić je na ekranie konsoli to jedna z podstawowych umiejętności jakie każdy musi posiadać.
Uważaj na typy danych
Język Python jest bardzo wygodny. Pozwala zapomnieć o tym, że niektóre czynności z punktu widzenia naszego komputera nie są tak proste i oczywiste. Na przykład łączenie dwóch ciągów tekstu w całość. W języku C trzeba było do tego używać dedykowanych funkcji i jeszcze często pamiętać o odpowiedniej alokacji pamięci. W Pythonie po prostu dwie zmienne zawierające tekst łączymy operatorem +
.
Ułatwienia jakie mamy w Pythonie czasem rozleniwiają i zapominamy, że zmienne mogą być różnego typu. Tylko w określonych przypadkach interpreter wie co ma zrobić. Wróćmy do kodu z poprzedniego artykułu. Za pomocą metody pozycja()
wyświetlamy wartości zmiennych x
oraz y
w naszej klasie, ale nie jako cyfry, ale jako sformatowany tekst:
(2,3)
Na wyświetlany tekst składają się oczywiście dwie cyfry, aktualne wartości zmiennych, lecz wyświetlamy je w ciągu tekstowym. Dlaczego więc nie zadziała poniższy zapis?
print("(" + self.x + "," + self.y + ")")
Traceback (most recent call last): File "", line 19, in File " ", line 11, in pozycja TypeError: can only concatenate str (not "int") to str
Z komunikatu błędy wyraźnie widzimy, że niedozwolone jest łączenie (konkatenacja) ze sobą zmiennych typu str
(ciąg znaków) oraz w naszym przypadku int
(liczby).
Łączenie ciągu znaków i liczby i formatowanie wyniku
Pokażę Ci teraz pięć metod na łączenie ze sobą ciągu znaków i liczby w jeden ciąg znaków, aby wypisać go na ekranie. W ten sam sposób możesz wynik połączenia przypisać do innej zmiennej. Spójrz na poniższe przykłady:
str() i __str__()
str()
to klasa systemowa służąca do obsługi zmiennych zawierających różne rodzaje tekstu. Dla uproszczenia w wielu publikacjach napisane jest, że to po prostu konwersja prawie dowolnego ciągu czy innej zmiennej na tekst. Można przyjąć takie uproszczenie, ale zapominamy wtedy o wbudowanych w klasę metodach pozwalających na prawie dowolne operacje na tekście. Zresztą sami zobaczcie w dokumentacji języka Python.
print("(" + str(self.x) + "," + str(self.y) + ")")
Jeżeli nie potrzebujemy przeprowadzać jakiś skomplikowanych operacji na utworzonym ciągu to możemy użyć funkcji __str__()
, która jest dostępna dla większości typów obiektów w języku Python. Stosując dziedziczenie możemy ją także nadpisać (overload) w naszej klasie. Jest ona powiązana z klasą str()
w ten sposób, że zwraca jej wartość w postaci tekstu.
print("(" + self.x.__str__() + "," + self.y.__str__() + ")")
W przypadku prostych, systemowych typów danych możemy obie metody używać naprzemiennie.
Formatowanie ciągu znaków
Poniższy zapis najbardziej przypomina konstrukcje stosowane w języku C. I działa dość podobnie, gdyż jest to formatowanie ciągu znaków za pomocą operatora %
(modulo).
print("(%s,%s)" % (self.x, self.y))
Technika ta zwana jest interpolacją i znana jest ze starszych wersji języka Python. W Python3 już nie zaleca się jej stosowania. Polega ona na tym, że w ciągu tekstowym umieszczamy informację o typie ciągu (u nas to %s
wskazujący na ciąg znakowy). Następnie po zamknięciu ciągu znaków (znajduje się on pomiędzy ""
lub ''
) po kolejnym znaku %
umieszczamy po kolei zmienne, które mają być sformatowane. Operatory formatowania opisane są w dokumentacji.
W wersji 3.6 języka Python została dodana funkcjonalność formatted string literal, w skrócie zwana też jako f-string. Jest to bardzo krótka w zapisie i elastyczna metoda pozwalająca na formatowanie ciągu znaków. Formatowaną zmienną (w naszym wypadku zmienianą na tekst) umieszczamy w nawiasach klamrowych. Wywołanie poprzedzamy literą f
lub F
na początku.
print(f'({self.x},{self.y})')
Metoda ta w przeciwieństwie do innych sposobów nie wymusza na programiście wiedzy o tym, ile potencjalnych danych będzie formatowanych. Daje zatem możliwość elastycznego konstruowania ciągów tekstu. Bardziej klasyczną metodą jest wywołanie funkcji format()
. Ta wymaga jednak podania jako argumenty dokładnie takiej liczby parametrów, ile pół formatowania wyznaczonych za pomocą {}
przewidzieliśmy, na dodatek w odpowiedniej kolejności.
print("({},{})".format(self.x, self.y))
Cześć
Dla funkcji format można zrobić mały workaround i wykorzystać keywords, wtedy nie trzeba podawać argumentów w kolejności:
Jest to też bardziej czytelne gdyby takich argumentów było więcej, nie trzeba wtedy liczyć nawiasów klamrowych żeby widzieć gdzie została wstawiona dana zmienna.
Przydaje się w Python2, bo fstring w Python3 są jeszcze lepsze i czytelniejsze.
Też jest to przydatna metoda, dzięki za jej umieszczenie 🙂