Generowanie liczb losowych i obsługa wyjątków w Pythonie

Python to język programowania wysokiego poziomu, którego celem jest połączenie czytelności kodu z możliwościami wyrażenia skomplikowanych koncepcji w zwięzły i klarowny sposób.

W tym tutorialu napiszemy prostą grę liczbową w której prosimy użytkownika o zgadnięcie liczby z zakresu 1-100, dając mu jedynie wskazówki czy szukana liczba jest większa czy mniejsza.

Losowanie liczby

Do losowania liczb pseudolosowych służy biblioteka random.

Operacje na liczbach

  • random() – zwraca liczbę zmiennoprzecinkową z zakresu 0.00 – 1.00 (zawsze mniejsza od 1.00)
  • uniform(10,40) – zwraca liczbę zmiennoprzecinkową z zakresu 10-40
  • triangular(10,40,30) – zwraca liczbę zmiennoprzecinkową z zakresu 10-40, ale zwiększa nieco prawdopodobieństwo wylosowania liczby bliższej 40.
  • randint(1,100) – zwróci liczbę typu integer z zakresu 1-100
  • randrange(1,10,2) – zwróci liczbę typu integer od 1-9. Ostatni opcjonalny parametr zawężą odpowiedź co 2-gi element, czyli losowanie będzie się odbywać dla liczb 1,3,5,7,9
  • getrandbits(16) – zwróci liczbę typu integer 16-bitową

Operacje na listach

Listy służą do przechowywania kolekcji elementów (takich jak liczby, napisy, inne listy itp.) w uporządkowany sposób np.

lista = ["Piotr", 8, "kokos", [5,2], 3.4, "44"]

Powyższa lista zawiera 6 elementów – trzy tekstowe (Piotr, kokos, 44), jedną liczbę zwykłą (8), jedną zmiennoprzecinkową (3.4) i listę, która zawiera dwie liczby 5 i 2.

  • choice(lista) – zwraca losowy element z listy
  • choices(lista, prawdopodobieństwa) – zwraca losowy element listy, ale dodatkowo pozwala na wybranie prawdopodobieństwa wylosowania poszczególnych elementów.
  • shuffle(lista) – zamienia losowo elementy na liście (ta funkcja zmienia listę, nie zwraca niczego)
  • sample(lista, 2) – zwraca dwa losowe elementy tablicy

Instrukcje sterujące generatorem liczb

Poniższe funkcje służą do sterowania generatorem liczb pseudolosowych.

  • seed(50) – wymusza samodzielną inicjalizację generatora liczb pseudolosowych
  • getstate()
  • setstate(state)

Generator potrzebuje jakiejś wartości do wygenerowania liczb. Domyślnie korzysta z aktualnego czasu systemowego, ale możemy mu przekazać dowolną liczbę (w powyższym przykładzie 50). Jeżeli nie zmienimy jej to każde losowanie będzie zwracało tą samą wartość.

Statystyka

Poniższe funkcje zwracają liczby zmiennoprzecinkowe według algorytmów używanych w statystyce. Nie będę ich omawiał szczegółowo.

  • betavariate()
  • expovariate(lambda)
  • gammavariate(alpha, beta)
  • gauss(mu, sigma)
  • lognormvariate(mu, sigma)
  • normalvariate (mu, sigma)
  • vonmisesvariate(mu, kappa)
  • paretovariate(alpha)
  • weibullvariate(alpha, beta)

Pierwszy kod

W poniższym kodzie importujemy niezbędną bibliotekę random, a następnie losujemy liczbę z zakresu 1-100. Dalej w pętli (która wykona się maksymalnie 10 razy) pytamy użytkownika o liczbę. To co zwróci użytkownik jest zawsze w formie tekstowej (string) dlatego zamieniamy wartość na liczbę (integer) z wykorzystaniem funkcji int(). W kolejnym kroku sprawdzamy czy to co podał użytkownik zgadza się z wylosowaną liczbą. Jeżeli tak to przerywamy pętlę przy użyciu funkcji break.

import random

compNr = random.randint(1, 100)
for i in range(10):

    userNr = int (input('Zgadnij liczbe 1-100: '))

    if userNr == compNr:
        print ("Zgadłeś!\n")
        break

    elif userNr > compNr:
        print ("Szukana liczba jest mniejsza\n")

    else:
        print ("Szukana liczba jest większa\n")

Wyjątki

Napisany poprzednio skrypt ma jedną zasadniczą wadę. Użytkownik może wpisać liczbę z poza zakresu 1-100, albo wręcz wpisać coś co nie jest wcale liczbą. Funkcja int zamieniająca na liczbę to co podał gracz spowoduje wówczas błąd, gdyż nie będzie potrafiła zamienić ciągu tekstowego na wartość integer. A to będzie skutkować przerwaniem programu.

By tego uniknąć możemy przejąć obsługę błędu. Do tego służą właśnie wyjątki. Poprawmy kod.

    while True:

        try:
            userNr = int (input('Zgadnij liczbe 1-100: '))

            if userNr < 1 or userNr > 100:
                raise Exception

            break

        except Exception:
            print ("BŁĄD: Podaj liczbę z zakresu 1-100\n")

Dodaliśmy pętlę nieskończoną, która będzie działała tak długo, aż użytkownik nie poda oczekiwanej wartości. Jeżeli tak się stanie pętla zostanie przerwana przy użyciu funkcji break.

Obsługa wyjątków znajduje się między try, a except. Wszystkie błędu, które wystąpią w tym bloku nie spowodują przerwania programu, a jedynie wywołanie kodu po except. Błąd typu Exception oznacza obsługę wszystkich rodzajów wyjątków, ale jeżeli wiemy jaki wyjątek może zwrócić dana funkcja to możemy obsłużyć konkretny problem. Funkcja int w przypadku błędu wywołuje wyjątek o nazwie ValueError.

while True:

        try:
            userNr = int (input('Zgadnij liczbe 1-100: '))

            if userNr < 1 or userNr > 100:
                raise ValueError

            break

        except ValueError:
            print ("BŁĄD: Podaj liczbę z zakresu 1-100\n")

        except KeyboardInterrupt:
            print ("Pa pa!")
            exit()

        except Exception:
            print ("BŁĄD: Wystąpił nieoczekiwany błąd")
            exit()

Jeżeli użytkownik poda liczbę z zakresu innego niż 1-100, wywołujemy również wyjątek ValueError za pomocą funkcji raise.

W powyższym przykładzie dodaliśmy jeszcze obsługę wyjątku w sytuacji w której gracz przerwie program używając CTRL+C (i naciśnie enter) – program wygeneruje wyjątek KeyboardInterrupt oraz kiedy coś innego się popsuje – wówczas powstanie ogólny wyjątek Exception.

Na zakończenie trzeba dodać jeszcze, że istnieje także blok finally, który możemy dodać na końcu programu (na równi z except). To co znajdzie się w tym bloku zostanie wywołane zawsze przed blokiem try.

Tradycyjnie kod na GitHub.

Podsumowanie

  1. Do losowania liczb możemy użyć biblioteki random.
  2. Przy użyciu tej biblioteki można losować liczby zwykłe, zmiennoprzecinkowe, a także wykonywać losowania na listach i wykonywać losowania zgodne z algorytmami używanymi w statystyce.
  3. Do wylosowania liczby typu integer możemy użyć random.randint
  4. Do zamiany tekstu na typ liczbowy integer służy funkcja int.
  5. Wyjątki obsługujemy za pomocą bloków try, except, finally