Moduły programistyczne

WPROWADZENIE

Podstawowym sposobem umieszczania kodu samosprawdzającego moduł Pythona jest wykorzystanie zmiennej __name__. Bardziej zaawansowane narzędzia testujące oferują moduły doctest i unittest z biblioteki standardowej. Moduł unittest2 to backport nowych możliwości z Pythona 2.7 do Pythona 2.4-2.6. Moduły nose i pytest to dodatkowe narzędzia do pisania testów z lekką składnią.

MODUŁ doctest

https://docs.python.org/3/library/doctest.html


def average(values):
    """Oblicza średnią arytmetyczną listy liczb.
    >>> average([20, 30, 70])
    40.0
    """
    return sum(values, 0.0) / len(values)

if __name__ == "__main__":
    import doctest
    doctest.testmod()   # automatyczne sprawdzanie wbudowanych testów

# Sprawdzanie przykładów podanych w pliku tekstowym.
# Zawartość pliku jet traktowana jako jeden wielki docstring.

import doctest
doctest.testfile("example.txt")

MODUŁ pytest

Moduł pytest należy do biblioteki standardowej od Pythona 3.6.


# Przykładowy plik z testami test_sample.py ('test' w nazwie pliku).

def inc(x):
    return x + 1

def test_answer():   # 'test' w nazwie funkcji
    assert inc(3) == 5   # intentional error, 'assert' is used

# Testy uruchamiamy w powłoce systemu operacyjnego poleceniem 'pytest',
# tak działa 'discovery mode'.

MODUŁ timeit

Moduł timeit służy do testowania czasu wykonania małych kawałków kodu. Do testowania większych bloków kodu istnieją inne narzędzia: profile, pstats.

Głównym elementem modułu jest klasa Timer(stmt="pass", setup="pass").
Metoda repeat(self, repeat=3, number=1000000) - wywołanie timeit() kilka razy (zwraca listę wyników).
Metoda timeit(self, number=1000000) - najpierw następuje pojedyncze wykonanie poleceń z setup, a potem number wykonań instrukcji z stmt.


import timeit
# help(timeit)

# Często przydaje się średnik do rozdzielania poleceń.
t1 = timeit.Timer(stmt="t=a ; a=b ; b=t", setup="a=1 ; b=2")
t2 = timeit.Timer(stmt="(a,b) = (b,a)", setup="a=1 ; b=2")
print(t1.timeit())         # domyślnie milion wykonań
print(t2.timeit())
print(t2.repeat(5))        # zwraca listę 5 wyników
print(min(t2.repeat(10)))  # to jest zwykle miarodajne, a nie średnia

import timeit

# Można budować polecenia wielowierszowe.
s = """\
pierwszy wiersz
drugi wiersz
"""
t = timeit.Timer(stmt=s)
print(t.timeit())

import random
import timeit

def mysort(L, left, right):
    L[left: right+1] = sorted(L[left: right+1])

lista = list(range(1000))
random.shuffle(lista)

t1 = timeit.Timer(stmt="mysort(lista, 0, len(lista)-1)", 
                  setup="from __main__ import mysort, lista")

print(t1.timeit(1))        # pojedyncze wykonanie

# Od Pythona 2.6 można przekazywać obiekty callable bez argumentów.

import random
import timeit

def mysort(L, left, right):
    L[left: right+1] = sorted(L[left: right+1])

lista = list(range(1000))
random.shuffle(lista)

t1 = timeit.Timer(lambda: mysort(lista, 0, len(lista)-1))

print(t1.timeit(1))        # pojedyncze wykonanie

MODUŁ enum

https://docs.python.org/3/library/enum.html

https://docs.python.org/3/howto/enum.html

PEP 0435 - Adding an Enum type to the Python standard library.
Typ Enum został dodany do Pythona 3.4


from enum import Enum
# from enum import IntEnum   # można porównywać z int

class Color(Enum):
    RED = 1   # zalecane jest użycie dużych liter do stałych
    GREEN = 2
    BLUE = 3

for c in Color:   # iteracja po enum
    print(c)
    #print(c.name, c.value)
# Color.RED
# Color.GREEN
# Color.BLUE

# Dostęp do koloru czerwonego:
Color(1)   # <Color.red: 1>
Color["RED"]   # jw