class Polygon: def is_simple(self): raise NotImplemented def area(self): raise NotImplemented def vertices(self): raise NotImplemented def bbox(self): V = self.vertices() X = [ v[0] for v in V ] Y = [ v[1] for v in V ] return ( min(X), min(Y), max(X), max(Y) ) def num_sides(self): return len(self.vertices()) def describe(self): return "A polygon with vertices {0}".format(self.vertices()) class SimplePolygon(Polygon): def is_simple(self): return True def area(self): a = 0.0 V = self.vertices() for i in range(len(V)-1): a += V[i][0] * V[i+1][1] - V[i+1][0]*V[i][1] return -0.5 * a class Square(SimplePolygon): def __init__(self, xll, yll, side): """A square with lower-left corner at (xll,yll) and given length on a side.""" self.__x = xll self.__y = yll self.__s = side def vertices(self): x0, y0, s = self.__x, self.__y, self.__s return ((x0, y0), (x0, y0+s), (x0+s, y0+s), (x0+s, y0), (x0, y0)) def describe(self): return "A {0}x{0} square with lower-left corner ({1},{2})" \ .format(self.__s, self.__x, self.__y) class Printable: """A mixin class for creating a __str__ method that prints a sequence object. Assumes that the type defines __getitem__.""" def left_bracket(self): return type(self).__name__ + "[" def right_bracket(self): return "]" def __str__(self): result = self.left_bracket() for i in range(len(self) - 1): result += str(self[i]) + ", " if len(self) > 0: result += str(self[-1]) return result + self.right_bracket() class MySeq(list, Printable): """A List with Benefits: out-of-range fetches return a default value.""" def __init__(self, default=None): self._default = default def __getitem__(self, k): try: return list.__getitem__(self, k) except: return self._default class Transformer: def mogrify(self): """Do something""" class CountedTransformer(Transformer): """A Transformer that counts the number of calls to its mogrify method.""" def __init__(self): self._count = 0 def mogrify(self): _count += 1 Transformer.mogrify(self) # Calls Transformer's method # Or super().mogrify() def count(self): return self._count