Выбрать главу

В качестве иллюстрации можно предположить, что создается модуль для вычисления простых чисел по алгоритму «решето Эратосфена». Модуль будет находиться в файле Sieve.py и состоять из одной функции primes(N), которая в результате своей работы дает все простые (не имеющие натуральных делителей кроме себя и единицы) числа от 2 до N:

import sets

import math

"""Модуль для вычисления простых чисел от 2 до N """

def primes(N):

 """Возвращает все простые от 2 до N"""

 sieve = sets.Set(range(2, N))

 for i in range(2, math.sqrt(N)):

  if i in sieve:

   sieve -= sets.Set(range(2*i, N, i))

 return sieve

Модуль pdb

Модуль pdb предоставляет функции отладчика с интерфейсом — командной строкой. Сессия отладки вышеприведенного модуля могла бы быть такой:

>>> import pdb

>>> pdb.runcall(Sieve.primes, 100)

> /home/rnd/workup/intuit–python/examples/Sieve.py(15)primes()

-> sieve = sets.Set(range(2, N))

(Pdb) l

10    import sets

11    import math

12    """Модуль для вычисления простых чисел от 2 до N """

13    def primes(N):

14     """Возвращает все простые от 2 до N"""

15 ->  sieve = sets.Set(range(2, N))

16     for i in range(2, int(math.sqrt(N))):

17      if i in sieve:

18       sieve -= sets.Set(range(2*i, N, i))

19     return sieve

20

(Pdb) n

> /home/rnd/workup/intuit–python/examples/Sieve.py(16)primes()

-> for i in range(2, int(math.sqrt(N))):

(Pdb) n

> /home/rnd/workup/intuit–python/examples/Sieve.py(17)primes()

-> if i in sieve:

(Pdb) n

> /home/rnd/workup/intuit–python/examples/Sieve.py(18)primes()

-> sieve -= sets.Set(range(2*i, N, i))

(Pdb) n

> /home/rnd/workup/intuit–python/examples/Sieve.py(16)primes()

-> for i in range(2, int(math.sqrt(N))):

(Pdb) p sieve

Set([2, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39,

41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79,

81, 83, 85, 87, 89, 91, 93, 95, 97, 99])

(Pdb) n

> /home/rnd/workup/intuit–python/examples/Sieve.py(17)primes()

-> if i in sieve:

(Pdb) n

> /home/rnd/workup/intuit–python/examples/Sieve.py(18)primes()

-> sieve -= sets.Set(range(2*i, N, i))

(Pdb) n

> /home/rnd/workup/intuit–python/examples/Sieve.py(16)primes()

-> for i in range(2, int(math.sqrt(N))):

(Pdb) p sieve

Set([2, 3, 5, 7, 11, 13, 17, 19, 23, 25, 29, 31, 35, 37, 41, 43, 47, 49,

53, 55, 59, 61, 65, 67, 71, 73, 77, 79, 83, 85, 89, 91, 95, 97])

Модуль profile

С помощью профайлера разработчики программного обеспечения могут узнать, сколько времени занимает исполнение различных функций и методов.

Продолжая пример с решетом Эратосфена, стоит посмотреть, как тратится процессорное время при вызове функции primes():

>>> profile.run("Sieve.primes(100000)")

        709 function calls in 1.320 CPU seconds

Ordered by: standard name

ncalls tottime percall cumtime percall filename:lineno(function)

     1   0.010   0.010   1.320   1.320 <string>:1(?)

     1   0.140   0.140   1.310   1.310 Sieve.py:13(primes)

     1   0.000   0.000   1.320   1.320 profile:0(Sieve.primes(100000))

     0   0.000           0.000         profile:0(profiler)

    65   0.000   0.000   0.000   0.000 sets.py:119(__iter__)

   314   0.000   0.000   0.000   0.000 sets.py:292(__contains__)

    65   0.000   0.000   0.000   0.000 sets.py:339(_binary_sanity_check)

    66   0.630   0.010   0.630   0.010 sets.py:356(_update)

    66   0.000   0.000   0.630   0.010 sets.py:425(__init__)

    65   0.010   0.000   0.540   0.008 sets.py:489(__isub__)

    65   0.530   0.008   0.530   0.008 sets.py:495(difference_update)

Здесь ncalls — количество вызовов функции или метода, tottime — полное время выполнения кода функции (без времени нахождения в вызываемых функциях), percall — тоже, в пересчете на один вызов, cumtime — аккумулированное время нахождения в функции, вместе со всеми вызываемыми функциями. В последнем столбце приведено имя файла, номер строки с функцией или методов и его имя.

Примечание:

«Странные» имена, например, __iter__, __contains__ и __isub__ — имена методов, реализующих итерацию по элементам, проверку принадлежности элемента (in) и операцию -=. Метод __init__ — конструктор объекта (в данном случае — множества).

Модуль unittest

При разработке программного обеспечения рекомендуется применять так называемые регрессионные испытания. Для каждого модуля составляется набор тестов, по возможности таким образом, чтобы проверялись не только типичные вычисления, но и «крайние», вырожденные случаи, чтобы испытания затронули каждую ветку алгоритма хотя бы один раз. Тест для данного модуля (написанный сразу после того, как определен интерфейс модуля) находится в файле test_Sieve.py: