Nie da się napisać programu, wchodzącego w interakcję z użytkownikiem, bez użycia komunikatów, lub zapytań. W języku Python te kwestie są bardzo uproszczone. Poznaliśmy już sposób prezentacji komunikatów na konsoli za pomocą słowa kluczowego print.

To co jest bardziej istotne, to wiedza jak manipulować tekstem, by przekazywane komunikaty były czytelniejsze, albo spełniały nasze założenia co do ich sformatowania.

Przypomnienie

W poprzednim temacie dotyczącym typów zaczęliśmy dyskutować nad różnymi sposobami dostosowywania wyjścia tak aby wyświetlić wynik konkatenowanego ciągu wraz z wartościami innego typu. Dla przypomnienia było to z wykorzystaniem listy parametrów: print(t1+" ma",p,t2); a także z konwersją (rzutowaniem) typu: print(t1+" ma "+str(p)+" "+t2), lub też z wykorzystaniem ciągów pre-formatowanych i tzw. iniekcji zmiennych: print((t1+" ma %s "+t2) %(p)), albo też dodatkowo z wykorzystaniem metody formatowania wyjścia: print((t1+" ma {0} "+t2).format(p)). W tym wszystkim dla “prostoty” wyjaśnienia tematu można dodać jeszcze jeden sposób z wykorzystaniem f-stringów1f-string od formated string tj.: print(t1+f" ma {p} "+t2).

Jak widać, sposobów jest wiele, ale który używać?? Odpowiedź na to pytanie jest złożona – pokrótce – tego, który nam najlepiej odpowiada. Niemniej jednak należy pamiętać, aby pisząc programy trzymać się jednego stylu – naszego stylu – który sobie w miarę nauki wyrabiamy. Bardzo źle widzianym jest mieszanie różnych metod, gdy nie zachodzi do tego istotna przesłanka2raczej nie potrafię znaleźć wytłumaczenia do takiego bigosu w kodzie. Zatem piszmy nasz program używając ujednoliconych metod, tworząc kod czytelniejszym, łatwiejszym do czytania i zrozumienia.

Zagadnienie jest bardzo obszerne i niniejszy rozdział nie wyczerpie tematu. Jest on raczej tylko wstępem i zachętą do jego zgłębienia jako już samodzielne pole rozwoju studenta. Generalnie ujmując syntaksa formatowania jest opisana w dokumentacji języka Python i punktem wyjścia jest zapoznanie się z opisem słów kluczowych print() oraz format(). Na potrzeby materiału dydaktycznego przećwiczymy kilka struktur oraz zagłębimy się w metody manipulowania nimi. Całość dokumentacji dotyczącej formatowania stringów znajduje się w opisie modułu string.

Słowo kluczowe: print()

Zacznijmy od syntaksy słowa kluczowego print(). Jego postać definicyjna przybiera następujący wygląd:

print(*objects, sep=' ', end='\n', file=None, flush=False)

gdzie widać wykorzystanie całej gamy parametrów.

Pierwszym naszym przykładem, gdzie się z tym spotkaliśmy było: print(t1+" ma",p,t2) z poprzedniego tematu. Tym niemniej było to wykorzystanie nadal niepełnych możliwości takiej funkcji, bowiem użyliśmy tylko listy obiektów do wyświetlenia. Były to: obiekt t1, tymczasowy, nienazwany obiekt: " ma"3Należy tutaj zauważyć, że podane w kodzie wartości o ile nie są przypisywane do zmiennych, to stanowią dla interpretera języka wskazówkę, że nie interesuje nas wielokrotne użycie zmiennej noszącej tę wartość. Jednakże i tak zostanie stworzony obiekt nienazwany o określonym i znanym środowisku identyfikatorze, który będzie przenosił wskazaną wartość i umożliwiał manipulację nią zgodnie z zasadami zdefiniowanymi dla obiektów zmiennych w języku. Aby się przekonać, że jest to prawda… wystarczy wpisać np. string “Ala ma kota” i wcisnąć kropkę, która w odniesieniu do obiektów służy do wskazania uruchamianej metody. W środowisku programistycznym PyCharm otworzy się lista podpowiedzi dostępnych metod., obiekt p oraz obiekt t2. Dotychczas nie używaliśmy innych parametrów i uzyskaliśmy poniższy efekt:

t1="To"
t2="formatowanie"
t3="stringa"
p=1
print(t1,str(p),"sposób na",t2,t3)

#------------- Wynik: 

To 1 sposób na formatowanie stringa

Process finished with exit code 0

Teraz użyjemy po kolei wszystkich parametrów i będziemy obserwować efekt. W tym celu wykonaj samodzielnie następujące zadania:

print(t1,str(p),"sposób na",t2,t3,sep="  ")
print(t1,str(p),"sposób na",t2,t3,sep=" | ", end="")

Jak się różni pierwsze działanie programu od drugiego?

Jak widać można używać tzw. delimiterów (separatorów) rozdzielających wypisywany tekst na sys.stdout4standardowe wyjście w zależności od naszych potrzeb. Przyda się to w dalszych przykładach i zadaniach. To czego nie widać od razu to parametr definiujący znak końca linii end="". To jest ciekawy aspekt, który pozwala na kontynuację wypisywania w tej samej linii, bez automatycznego przejścia do linii następnej. Zważ następujący przykład obu programów i rezultat ich działania:

t1="Ala"
t2="ma"
t3="kota"

print(t1)
print(t2)
print(t3)
t1="Ala"
t2="ma"
t3="kota"

print(t1,end=" ")
print(t2,end=" ")
print(t3,end="\n\r")

I co zauważyłeś?? Teraz już wiesz jak można formować wypisywany komunikat niejako “po kawałku”, zanim przejdziesz do nowej linii. Używając parametrów trzeba pamiętać, że zmieniają one tylko działanie tej instrukcji w której zostały użyte, potem na powrót używane są ustawienia standardowe. Parametr end definiuje string wyświetlany na końcu działania komendy print. Możesz użyć tutaj, jak w powyższym przykładzie, wymuszenia wykorzystania spacji i kontynuowania wypisywania w tej samej linii; a w ostatniej komendzie zakończenie wypisywania znakami sterującymi \n\r5znaki sterujące (control code) znajdują się w tablicy ASCII od wartości 0 do 31 (heksadecymalnie 0x00÷0x1f) oraz kod DEL o wartości 127 (hex: 0x7F) i pełnią konkretne funkcje sterujące terminalem wyjściowym np. znak \n (kod znaku o wartości dziesiętnej 10) to przejście do nowej linii, znak \r (kod znaku o wartości dziesiętnej 13) – powrót na początek linii, a \t (kod znaku o wartości dziesiętnej 9) – to znak tabulacji.

  1. Zadanie do wykonania: Powtórz wyżej przedstawione zagadnienia i przećwicz w programie użycie różnych parametrów (włącznie z próbą wykorzystania znaków sterujących) np. samo \r itp.
  2. Zadanie do wykonania: Napisz program, w którym zdefiniujesz listę 5 nazwisk. Teraz wyświetl je wszystkie obok siebie, oddzielając poszczególne kolumny pionową kreską. (podpowiedź: skorzystaj z przykładu odpowiednich struktur zaprezentowanego w poprzednim temacie.

Patrząc na powyższe zadanie przypominamy sobie konstrukcję pętli for-each potrzebną nam do zrealizowania zadania w sposób efektywny. Dla sprawdzenia swojej pracy zweryfikuj podobieństwa i różnice z kodem zaprezentowanym poniżej. O hasło zapytaj prowadzącego.

To pierwsze poważniejsze zadanie, wpierw zmierz się z wyzwaniem, potem zweryfikujesz wynik
To view this protected content, enter the password below:

Temat pętli będzie kontynuowany w innym wątku, jednakże na potrzeby tego materiału wprowadziliśmy już używaną formułę. Dodatkowo może nam przydać się jeszcze zagadnienie zapytania warunkowego. Dlatego też poniżej w krótkiej demonstracji zaprezentowany został kod dokonujący sprawdzenia, czy w zdaniu (stringu) poszczególne znaki są literami, i jeśli zostanie wykryta cyfra – to zastąpiona zostanie literą D.

zdanie="Ala ma 3 koty i 2 z nich to kocury, a 1 to kotka"
for i in zdanie:
    if i.isdigit(): print("D",end="")
    else: print(i,end="")

#lub

for i in zdanie:
    if ord(i) in range(ord('0')-1,ord('9')+1): print("D",end="")
    else: print(i,end="")

Tutaj należy przede wszystkim podkreślić, że omówienie wyrażeń warunkowych odbędzie się w odrębnym miejscu kursu. Na potrzeby jednak niniejszych wysiłków, na szybko omówimy pospolite Jeżeli czyli słowo kluczowe if. Czyniąc w programie test piszemy słowo kluczowe if, i następnie podajemy warunek korzystając z logiki matematycznej lub porównań arytmetycznych6jeśli warunek jest złożony to tworzymy go blokując poszczególne człony za pomocą nawiasów i spinając je razem za pomocą wyrażeń logicznych. Po warunku część egzekucyjną oddzielamy dwukropkiem : i piszemy linię kodu do wykonania w przypadku gdy warunek jest spełniony. Jeśli… potrzebujemy kilku linii, to musimy pamiętać o stosowaniu wcięcia w tekście, każda nowa linia tego bloku kodu zaczynać się powinna od 4 spacji. Jeśli potrzebujemy jakieś działanie w zaistnieniu przeciwnego wypadku – kod będący jego realizacją rozpoczynamy od słowa else: umieszczonego dokładnie w tej samej kolumnie co if. Reszta założeń powtarza się. Najprostszy przykład wykorzystania wyrażenia warunkowego jest zamieszczony poniżej:

if 10>15: print("10 jest większe od 15")
else: print("10 nie jest większe od 15")

Zadania do wykonania

  1. Zadanie 3: Napisz program, który wypisze wszystkie litery alfabetu łacińskiego,
  2. Zadanie 4: Napisz program, który sprawdzi strukturę umieszczonej w programie zmiennej zdanie="Ala ma 3 koty, 2 psy, 1 chomika" i wypisze oddzielnie w osobnych 4 kolejnych liniach: wartość całej zmiennej; wszystkie duże litery; wszystkie małe litery; oraz cyfry.
  3. Zadanie 5: Napisz program, który wyświetli predefiniowane zdanie, a następnie zmieni wszystkie litery na duże.

Rozwiązania zadań są poniżej.

Zadanie 3

Spytaj prowadzącego o hasło
To view this protected content, enter the password below:

Zadanie 4

Spytaj prowadzącego o hasło
To view this protected content, enter the password below:

Zadanie 5

Spytaj prowadzącego o hasło
To view this protected content, enter the password below:

Co z tym formatowaniem

Powyższe przykłady i zadania dotyczyły typu string – łańcucha tekstowego. Jednakże już w poprzednim module występowały przykłady mieszania danych liczbowych z tekstowymi i do tego pojawiały się niepokojąco dziwne zapisy z wykorzystaniem nawiasów klamrowych, procentów itp. Nadszedł czas aby uchylić rąbka tajemnicy.

Rozpatrzmy przypadek już wyżej roztrząsany – listy nazwisk. Rozbudujmy tę listę do małej bazy danych. Kod przedstawiony jest poniżej:

list=(("Kowalski","Jan",2008),("Antecki","Wojciech",1987),("Magdziarz","Marek",1999),("Wolny","Maciej",2003),("Burda","Wiktoria",2007))
for i in list:
    for ii in i: print(ii,end=" | ")
    print()

Wynik działania widać poniżej:

Kowalski | Jan | 2008 | 
Antecki | Wojciech | 1987 |
Magdziarz | Marek | 1999 |
Wolny | Maciej | 2003 |
Burda | Wiktoria | 2007 |

Process finished with exit code 0

Jak da się zauważyć, niezbędne dane z sukcesem wyświetliliśmy. To co się nie do końca udało to dochowanie estetyki, co prócz działającego programu, jest drugim równie ważnym sukcesem (albo porażką). Estetyka wpływa na odbiór przez użytkownika i czytelność komunikatów jakie chcemy mu przekazać. Tutaj praktycznie nie ma w ogóle miejsca formatowanie danych. Spróbujmy zatem coś z tym zrobić.

Poniżej zamieszczony został wyciąg z dokumentacji formatowania w łańcuchu znakowym:

format_spec     ::=  [[fill]align][sign]["z"]["#"]["0"][width][grouping_option]["." precision][type]
fill ::= <any character>
align ::= "<" | ">" | "=" | "^"
sign ::= "+" | "-" | " "
width ::= digit+
grouping_option ::= "_" | ","
precision ::= digit+
type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"

Wykorzystajmy te podpowiedzi do poprawienia naszego programu:

list=(("Kowalski","Jan",2008),("Antecki","Wojciech",1987),("Magdziarz","Marek",1999),("Wolny","Maciej",2003),("Burda","Wiktoria",2007))
for i in list:
    for ii in i: print(ii.__format__(" <10"),end=" | ")
    print()

Uzyskaliśmy wynik:

Kowalski   | Jan        | 2008       | 
Antecki | Wojciech | 1987 |
Magdziarz | Marek | 1999 |
Wolny | Maciej | 2003 |
Burda | Wiktoria | 2007 |

Process finished with exit code 0

Udało się nam zatem uporządkować kolumny nadając im szerokość 10 znaków, oraz wyrównując ich zawartość do lewej. Spróbuj innych konfiguracji wyrównania <, >, ^. Co uzyskałeś? A teraz poeksperymentuj z szerokością kolumn… i jak… widać, że w naszym przykładzie mniejsza szerokość jak 9 znaków powoduje “rozsypanie się” ładnego rozmieszczenia w tabeli. Przypisywanie jednak na stałe wartości szerokości kolumny jest ryzykowne, bowiem, co w przypadku gdy w pewnym momencie zmieni się długość jakiejś wartości ponad założoną szerokość?! Wtedy znów wkradnie się w nasz program niechlujność… Należałoby zmodyfikować program tak, aby sam zweryfikował jaką szerokość kolumn potrzebuje. Tutaj przychodzi nam z pomocą kolejna metoda modułu string a mianowicie __len__().

print(nazwisko+" ma "+str(nazwisko.__len__())+" liter.")

Zadanie z Wierzchosławą Konstatynowiczówną

Teraz możemy pokusić się już o napisanie programu, który ureguluje nam dynamicznie zmieniające się długości ciągów tekstowych zabezpieczając, by Wierzchosława Konstantynowiczówna była ładnie wyświetlana w naszym programie… Spróbujesz samemu napisać ten kod??

Spytaj prowadzącego o hasło
To view this protected content, enter the password below:

Zadanie 7

Napisz program, który wyświetli tabliczkę mnożenia korzystając z predefiniowanej 10-elementowej tablicy zawierających liczby od 1 do 10. Wynik działania powinien wyglądać następująco:

    1    2    3    4    5    6    7    8    9   10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
6 12 18 24 30 36 42 48 54 60
7 14 21 28 35 42 49 56 63 70
8 16 24 32 40 48 56 64 72 80
9 18 27 36 45 54 63 72 81 90
10 20 30 40 50 60 70 80 90 100

Process finished with exit code 0

Spytaj prowadzącego o hasło
To view this protected content, enter the password below:

Zadanie 8

Napisz program, który wyświetli wartości predefiniowanej liczby i w zapisie dziesiętnym, binarnym, oktalnym i heksadecymalnym oraz odpowiadający jej wartości kod ASCII. Wynik działania powinien wyglądać analogicznie:

Znak ASCII: A, Decymalnie:___65, binarnie:___1000001, oktalnie:_______101, hex:________41

Process finished with exit code 0

Spytaj prowadzącego o hasło
To view this protected content, enter the password below: