1.2. Duży Lotek¶
Zakładamy, że znasz już podstawy podstaw :-) Pythona, czyli scenariusz Mały Lotek.
Jedna liczba to za mało, wylosujmy ich więcej! Zasady dużego lotka to typowanie 6 liczb z 49. Ponieważ trafienie jest tu bardzo trudne, napiszemy program w taki sposób, aby można było łatwo dostosować poziom jego trudności.
Na początek
- Utwórz nowy plik
toto2.py
i uzupełnij go wymaganymi liniami wskazującymi interpreter pythona i użyte kodowanie. - Wykorzystując funkcje
input()
orazint()
pobierz od użytkownika ilość liczb, które chce odgadnąć i zapisz wartość w zmiennejileliczb
. - Podobnie jak wyżej pobierz od użytkownika i zapisz maksymalną losowaną liczbę w zmiennej
maksliczba
. - Na koniec wyświetl w konsoli komunikat “Wytypuj ileliczb z maksliczba liczb: ”.
Wskazówka
Do wyświetlenia komunikatu można użyć konstrukcji: print("Wytypuj", ileliczb, "z", maksliczba, " liczb: ")
.
Jednak wygodniej korzystać z operatora %
. Wtedy instrukcja przyjmie postać:
print("Wytypuj %s z %s liczb: " % (ileliczb, maksliczba))
. Symbole zastępcze %s
zostaną zastąpione kolejnymi wartościami z listy podanej po operatorze %
.
Najczęściej używamy symboli: %s
– wartość zostaje zamieniona na napis przez funkcję
str()
; %d
– wartość ma być dziesiętną liczbą całkowitą; %f
– oczekujemy liczby
zmiennoprzecinkowej.
1.2.1. Listy¶
1.2.1.1. Ćwiczenie¶
Jedną wylosowaną liczbę zapamiętywaliśmy w jednej zmiennej, ale przechowywanie wielu wartości w osobnych zmiennych nie jest dobrym pomysłem. Najwygodniej byłoby mieć jedną zmienną, w której można zapisać wiele wartości. W Pythonie takim złożonym typem danych jest lista.
Przetestuj w interpreterze następujące polecenia:
~$ python3
>>> liczby = []
>>> liczby
>>> liczby.append(1)
>>> liczby.append(2)
>>> liczby.append(4)
>>> liczby.append(4)
>>> liczby
>>> liczby.count(1)
>>> liczby.count(4)
>>> liczby.count(0)
Wskazówka
Klawisze kursora (góra, dół) służą w terminalu do przywoływania poprzednich poleceń. Każde przywołane polecenie możesz przed zatwierdzeniem zmienić używając klawiszy lewo, prawo, del i backspace.
Jak widać po zadeklarowaniu pustej listy (liczby = []
), metoda .append()
pozwala dodawać do niej wartości, a metoda .count()
podaje, ile razy
dana wartość wystąpiła w liście. To się nam przyda ;-)
Wróćmy do programu i pliku toto2.py
, który powinien w tym momencie wyglądać tak:
1 2 3 4 5 6 7 8 9 | #!/usr/bin/env python3
# -*- coding: utf-8 -*-
import random
ileliczb = int(input("Podaj ilość typowanych liczb: "))
maksliczba = int(input("Podaj maksymalną losowaną liczbę: "))
# print("Wytypuj", ileliczb, "z", maksliczba, " liczb: ")
print("Wytypuj %s z %s liczb: " % (ileliczb, maksliczba))
|
Kodujemy dalej. Użyj pętli:
- dodaj instrukcję
for
, aby wylosowaćileliczb
z zakresu ograniczonego przezmaksliczba
; - kolejne losowane wartości drukuj w terminalu;
- sprawdź działanie kodu.
Trzeba zapamiętać losowane wartości:
- przed pętlą zadeklaruj pustą listę;
- wewnątrz pętli umieść polecenie dodające wylosowane liczby do listy;
- na końcu programu (uwaga na wcięcia) wydrukuj zawartość listy;
- kilkukrotnie przetestuj program.
1.2.2. Pętla while¶
Czy lista zawsze zawiera akceptowalne wartości?
Pętla for
nie nadaje się do losowania unikalnych liczb, ponieważ wykonuje się określoną ilość razy,
a nie możemy zagwarantować, że losowane liczby będą za każdym razem inne.
Do wylosowania podanej ilości liczb wykorzystamy więc pętlę while wyrażenie_logiczne:
,
która powtarza kod dopóki podane wyrażenie jest prawdziwe.
Uzupełniamy kod w pliku toto2.py
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #!/usr/bin/env python3
# -*- coding: utf-8 -*-
import random
ileliczb = int(input("Podaj ilość typowanych liczb: "))
maksliczba = int(input("Podaj maksymalną losowaną liczbę: "))
# print("Wytypuj %s z %s liczb: " % (ileliczb, maksliczba))
liczby = []
# for i in range(ileliczb):
i = 0
while i < ileliczb:
liczba = random.randint(1, maksliczba)
if liczby.count(liczba) == 0:
liczby.append(liczba)
i = i + 1
print("Wylosowane liczby:", liczby)
|
Losowane liczby zapamiętujemy w liście liczby
. Zmienna i
to
licznik unikalnych wylosowanych liczb, korzystamy z niej w wyrażeniu
warunkowym i < ileliczb
, które kontroluje powtórzenia pętli. W instrukcji
warunkowej wykorzystujemy funkcję zliczającą wystąpienia wylosowanej wartości
w liście (liczby.count(liczba)
), aby dodawać (liczby.append(liczba)
)
do listy tylko liczby wcześniej niedodane.
1.2.3. Zbiory¶
Przy pobieraniu typów użytkownika użyjemy podobnie jak przed chwilą pętli
while
, ale typy zapisywać będziemy w zbiorze, który z założenia nie
może zawierać duplikatów (zob. zbiór).
1.2.3.1. Ćwiczenie¶
W interpreterze Pythona przetestuj następujące polecenia:
~$ python3
>>> typy = set()
>>> typy.add(1)
>>> typy.add(2)
>>> typy
>>> typy.add(2)
>>> typy
>>> typy.add(0)
>>> typy.add(9)
>>> typy
Pierwsza instrukcja deklaruje pusty zbiór (typy = set()
). Metoda .add()
dodaje do zbioru elementy, ale nie da się dodać dwóch takich samych elementów.
Drugą cechą zbiorów jest to, że ich elementy nie są w żaden sposób uporządkowane.
Wykorzystajmy zbiór, aby pobrać od użytkownika typy liczb. W pliku
toto2.py
dopisujemy:
20 21 22 23 24 25 26 27 | print("Wytypuj %s z %s liczb: " % (ileliczb, maksliczba))
typy = set()
i = 0
while i < ileliczb:
typ = input("Podaj liczbę %s: " % (i + 1))
if typ not in typy:
typy.add(typ)
i = i + 1
|
Zauważ, że operator in
pozwala sprawdzić, czy podana liczba
jest (if typ in typy
) lub nie (if typ not in typy:
) w zbiorze.
Przetestuj program.
1.2.4. Operacje na zbiorach¶
Określenie ilości trafień w większości języków programowania wymagałoby przeszukiwania listy wylosowanych liczb dla każdego podanego typu. W Pythonie możemy użyć arytmetyki zbiorów: wyznaczymy część wspólną.
1.2.4.1. Ćwiczenie¶
W interpreterze przetestuj poniższe instrukcje:
~$ python3
>>> liczby = [1,3,5,7,9]
>>> typy = set([2,3,4,5,6])
>>> set(liczby) | typy
>>> set(liczby) - typy
>>> trafione = set(liczby) & typy
>>> trafione
>>> len(trafione)
Polecenie set(liczby)
przekształca listę na zbiór. Kolejne operatory
zwracają sumę (|
), różnicę (-
) i iloczyn (&
), czyli część
wspólną zbiorów. Ta ostania operacja bardzo dobrze nadaje się do sprawdzenia,
ile liczb trafił użytkownik. Funkcja len()
zwraca ilość elementów
każdej sekwencji, czyli np. napisu, listy czy zbioru.
Do pliku toto2.py
dopisujemy:
31 32 33 34 35 36 | trafione = set(liczby) & typy
if trafione:
print("\nIlość trafień: %s" % len(trafione))
print("Trafione liczby: ", trafione)
else:
print("Brak trafień. Spróbuj jeszcze raz!")
|
Instrukcja if trafione:
sprawdza, czy część wspólna zawiera jakiekolwiek elementy.
Jeśli tak, drukujemy liczbę trafień i trafione liczby.
Przetestuj program dla 5 typów z 10 liczb. Działa? Jeśli masz wątpliwości, wpisz wylosowane i wytypowane liczby w interpreterze, np.:
>>> liczby = [1,4,2,6,7]
>>> typy = set([1,2,3,4,5])
>>> trafione = set(liczby) & typy
>>> if trafione:
... print(len(trafione))
...
>>> print(trafione)
Wnioski? Logika kodu jest poprawna, czego dowodzi test w terminalu, ale program nie działa. Dlaczego?
Wskazówka
Przypomnij sobie, jakiego typu wartości zwraca funkcja input()
i użyj we właściwym miejscu funkcji int()
.
Wynik działania programu powinien wyglądać następująco:
1.2.4.2. Do 3 razy sztuka¶
Zastosuj pętlę for
tak, aby użytkownik mógł 3 razy typować liczby z tej
samej serii liczb wylosowanych. Wynik działania programu powinien przypominać
poniższy zrzut:
1.2.5. Błędy i wyjątki¶
Kod naszego programu do tej pory przedstawia się mniej więcej tak:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #!/usr/bin/env python3
# -*- coding: utf-8 -*-
import random
ileliczb = int(input("Podaj ilość typowanych liczb: "))
maksliczba = int(input("Podaj maksymalną losowaną liczbę: "))
liczby = []
i = 0
while i < ileliczb:
liczba = random.randint(1, maksliczba)
# print("Wylosowane liczba: %s " % liczba)
if liczby.count(liczba) == 0:
liczby.append(liczba)
i = i + 1
for i in range(3):
print("Wytypuj %s z %s liczb: " % (ileliczb, maksliczba))
typy = set()
i = 0
while i < ileliczb:
typ = int(input("Podaj liczbę %s: " % (i + 1)))
if typ not in typy:
typy.add(typ)
i = i + 1
trafione = set(liczby) & typy
if trafione:
print("\nIlość trafień: %s" % len(trafione))
print("Trafione liczby: ", trafione)
else:
print("Brak trafień. Spróbuj jeszcze raz!")
print("\n" + "x" * 40 + "\n") # wydrukuj 40 znaków x
print("Wylosowane liczby:", liczby)
|
Uruchom powyższy program i podaj ilość losowanych liczb większą od maksymalnej losowanej liczby. Program wpada w nieskończoną pętlę! Po chwili zastanowienia dojdziemy do wniosku, że nie da się wylosować np. 6 unikalnych liczb z zakresu 1-5.
1.2.5.1. Ćwiczenie¶
- Użyj w kodzie instrukcji warunkowej, która w przypadku gdy użytkownik chciałby wylosować więcej liczb
niż podany zakres maksymalny, wyświetli komunikat “Błędne dane!” i przerwie wykonywanie programu
za pomocą funkcji
exit()
.
Testujemy dalej. Uruchom program i zamiast liczby podaj tekst. Co się dzieje? Uruchom jeszcze raz, ale tym razem jako typy podaj wartości spoza zakresu <0;maksliczba>. Da się to zrobić?
Jak pewnie zauważyłeś, w pierwszym wypadku zgłoszony zostaje wyjątek ValuError
(zob.: wyjątki) i komunikat invalid literal for int() with base 10
,
który informuje, że funkcja int()
nie jest w stanie przekształcić podanego
ciągu znaków na liczbę całkowitą. W drugim wypadku podanie nielogicznych
typów jest możliwe.
Uzupełnijmy program tak, aby był nieco odporniejszy na niepoprawne dane:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | #!/usr/bin/env python3
# -*- coding: utf-8 -*-
import random
try:
ileliczb = int(input("Podaj ilość typowanych liczb: "))
maksliczba = int(input("Podaj maksymalną losowaną liczbę: "))
if ileliczb > maksliczba:
print("Błędne dane!")
exit()
except ValueError:
print("Błędne dane!")
exit()
liczby = []
i = 0
while i < ileliczb:
liczba = random.randint(1, maksliczba)
if liczby.count(liczba) == 0:
liczby.append(liczba)
i = i + 1
for i in range(3):
print("Wytypuj %s z %s liczb: " % (ileliczb, maksliczba))
typy = set()
i = 0
while i < ileliczb:
try:
typ = int(input("Podaj liczbę %s: " % (i + 1)))
except ValueError:
print("Błędne dane!")
continue
if 0 < typ <= maksliczba and typ not in typy:
typy.add(typ)
i = i + 1
trafione = set(liczby) & typy
if trafione:
print("\nIlość trafień: %s" % len(trafione))
print("Trafione liczby: ", trafione)
else:
print("Brak trafień. Spróbuj jeszcze raz!")
print("\n" + "x" * 40 + "\n") # wydrukuj 40 znaków x
print("Wylosowane liczby:", liczby)
|
Do przechwytywania wyjątków używamy konstrukcji try: ... except wyjątek: ...
, czyli:
spróbuj wykonać kod w bloku try
, a w razie błędów przechwyć wyjątek
i wykonaj
podporządkowane instrukcje. W powyższych przypadkach przechwytujemy wyjątek ValueError
,
wyświetlamy odpowiedni komunikat i kończymy działanie programu (exit()
) lub
wymuszamy ponowne wykonanie pętli (continue
) zamiast ją przerywać (break
).
Poza tym sprawdzamy, czy użytkownik podaje sensowne typy. Warunek if 0 < typ <= maksliczba:
to skrócony zapis wyrażenia logicznego z użyciem operatora koniunkcji:
typ > 0 and typ <= maksliczba
. Sprawdzamy w ten sposób, czy wartość zmiennej
typ
jest większa od zera i mniejsza lub równa wartości zmiennej maksliczba
.
1.2.6. Materiały¶
Źródła:
Materiały Python 101
udostępniane przez
Centrum Edukacji Obywatelskiej na licencji
Creative Commons Uznanie autorstwa-Na tych samych warunkach 4.0 Międzynarodowa.
Utworzony: | 2022-05-22 o 19:52 w Sphinx 1.5.3 |
---|---|
Autorzy: | Patrz plik “Autorzy” |