Prosta hierarchia klas: obliczenia statystyczne

W poniższym przykładzie powstanie kilka klas, umożliwiających obliczenia statystyczne na kolumnie liczb. Każda z klas ma jasno sprecyzowany cel, a funkcjonalność, którą dostarcza, zaimplementowana jest w operatorze wywołania (call operator). Dodatkowo każda z tych klas umie się przedstawić (metoda name())

Klasy dziedziczą po abstrakcyjnej klasie bazowej AbstractStatistCalculator, która definiuje metody, zaimplementowane w klasach potomnych. Najciekawszym przypadkiem jest klasa SumVariance, która zarówno zawiera obiekty klasy AbstractStatistCalculator jak i sama po niej dziedziczy. Również sama nie wykonuje żadnych obliczeń. Wymaganą funkcjonalność zapewnia, wywołując odpowiednie metody ze składowych obiektów (delegacje).

 1class AbstractStatistCalculator:
 2
 3    def __call__(self, *args):
 4        raise NotImplemented("to be implemented in by a derived class")
 5
 6    def name(self, *args):
 7        raise NotImplemented("to be implemented in by a derived class")
 8
 9
10class Sum(AbstractStatistCalculator):
11
12    def __call__(self, *args):
13        if len(args) == 1: args = args[0]
14        s = 0
15        for v in args: s+=v
16        return s
17
18    def name(self, *args):
19        return "             sum"
20
21class Average(AbstractStatistCalculator):
22
23    def __call__(self, *args):
24        if len(args) == 1: args = args[0]
25        s = 0
26        for v in args: s+=v
27        return s/len(args)
28
29    def name(self, *args):
30        return "         average"
31
32
33class Variance(AbstractStatistCalculator):
34
35    def __call__(self, *args):
36        if len(args) == 1: args = args[0]
37        s, s2 = 0, 0
38        for v in args:
39            s += v
40            s2 += v * v
41        s = s/len(args)
42        return s2/len(args) - s*s
43
44    def name(self, *args):
45        return "        variance"
46
47
48class SumVariance(AbstractStatistCalculator):
49
50    def __init__(self):
51        self.__avg = Sum()
52        self.__var = Variance()
53
54    def __call__(self, *args):
55        return self.__avg(*args), self.__var(*args)
56
57    def name(self, *args):
58        return "sum and variance"
59
60
61if __name__ == "__main__":
62
63    from random import random
64
65    sum = Sum()
66    avg = Average()
67    var = Variance()
68
69    stats = [sum, avg, var, SumVariance()]
70    input_data = [random() for i in range(100)]
71
72    for calc in stats:
73        print(calc.name()+" :",calc(input_data))