fork download
  1. import math
  2. import random
  3.  
  4. COLOURS = ['black', 'yellow', 'red', 'magenta', 'cyan', 'purple']
  5.  
  6. class Square(object):
  7. # строки 6-37 это лишь описание класса, образец, blueprint, если угодно,
  8. # но сам он не является объектом (инстансом) квадрата.
  9. # А вот вызвывая "Square()" уже и создаётся квадрат. Каждый раз — новый,
  10. # с теми параметрами (стороны и цвета), которые были переданы в аргументами.
  11. def __init__(self, side, colour="black"):
  12. self.side = side
  13. self.colour = colour
  14.  
  15. @classmethod
  16. def generate_random(cls, colours):
  17. # Это классовый метод, в котором первым аргументом передаётся не инстанс
  18. # класса (то, что в методах 'self' обозначается), а сам класс/тип.
  19. # Т.е. в данном случае cls == Square, а выражение cls(side, colour)
  20. # эквивалентно Square(side, colour). Разница появляется при налседовани, где
  21. # cls уже будет тем классом, без необходимости заново объявлять этот метод.
  22. # В ромбе-алмазе увидишь, как работает.
  23. # Ссылаться на глобальные переменные как-то не круто, я подумал, поэтому
  24. # решил добавить аргумент с массивом цветов, так как это универсальный аргумент
  25. # среди всех фигур.
  26. side = random.random() * 100
  27. colour = colours[random.randint(0, len(colours) - 1)]
  28. return cls(side, colour)
  29.  
  30. def area(self):
  31. # на метод изменил, чтобы с проперти тебя не путать — потом почитаешь про них
  32. return self.side ** 2
  33.  
  34. def description(self):
  35. # Возвращает строку с описанием объекта, при вызове этого метода у
  36. # конкретного объекта (инстанса класса Square или любого из унаследовавших)
  37. # __class__.__name__ — чтобы было написано название именно класса объекта,
  38. # а не то, что я тут впишу текстом, но при этом и не было необходимости
  39. # создавать лишние классовые переменные при наследовании. Это на вкус уже,
  40. # конечно, потому что может нужно в тексте иметь "triangle", а класс назвать
  41. # Trngl. Нутыпонел, в общем, просто полезную штучку показать решил.
  42. # В ромбе-алмазе увидишь, как работает.
  43. return "%s %s with side: %.2f, area: %.2f" % (self.colour.title(),
  44. self.__class__.__name__.lower(), self.side, self.area())
  45.  
  46. class Circle(object):
  47. def __init__(self, radius, colour="black"):
  48. self.radius = radius
  49. self.colour = colour
  50.  
  51. @classmethod
  52. def generate_random(cls, colours):
  53. radius = random.random() * 100
  54. colour = colours[random.randint(0, len(colours) - 1)]
  55. return cls(radius, colour)
  56.  
  57. def area(self):
  58. return self.radius ** 2 * math.pi
  59.  
  60. def description(self):
  61. return "%s %s with radius: %.2f, area: %.2f" % (self.colour.title(),
  62. self.__class__.__name__.lower(), self.radius, self.area())
  63.  
  64. class Diamond(Square):
  65. # ромб (у которого все стороны равны, как у квадрата), но имеющий углы по
  66. # 60 и 120 градусов.
  67. def area(self):
  68. return self.side ** 2 * math.sin(math.pi * (60/180))
  69.  
  70.  
  71. # Если сначала просто вручную создадим парочку.
  72. s1 = Square(5) # квадрат со стороной 5 и чёрным (дефолтным) цветом.
  73. s2 = Square(10, "yellow") # жёлтый квадрат со стороной 10.
  74. # Никаки строк текста никуда пока не писалось, но за s1 и s2 стоят самые настоящие
  75. # квадратики, с которым можно что угодно делать. Был бы у них метод draw(), сейчас
  76. # бы я мог их нарисовать. Или не сейчас.
  77. # А вот теперь я хочу посмотреть описание второго квадрата:
  78. print(s2.description())
  79.  
  80. # Теперь к генератору перейдём
  81. classes = [Square, Circle, Diamond]
  82. # Это просто список всех классов (_типов_ фигур). Я их туда запихнул для лупа
  83. # дальнейшего лупа по этом списку и генерации их всех за один проход. Можно, конечно,
  84. # и как ты - отдельно каждого класса создавать, а потом перемешать, но представь,
  85. # что у тебя 100 таких классов - задолбаешься на каждый из них пускай даже по 5, но
  86. # одинаковых строк тратить. А так запихнул в список и прекрасно.
  87.  
  88.  
  89. figs = [] # вот это как вот раз список _фигур_ (таких объектов, как s1 и s2)
  90. numfigs = 5
  91.  
  92. # Дальше создадим десяток их (numfigs = 5, но по две за одну итерацию создаётся)
  93. for i in range(numfigs):
  94. fig = classes[random.randint(0, len(classes) - 1)]
  95. # fig - просто рандомный класс из списка выше.
  96. # В данные момент, например, может быть, что fig == Circle.
  97.  
  98. side_or_rad = random.random() * 100
  99. colour = COLOURS[random.randint(0, len(COLOURS) - 1)]
  100. # Так как у нас все фигуры имеют одинаковый "вид" создания: длина/радиус и цвет,
  101. # можно не делать отдельно функции для каждого, а просто сгенерить случайные
  102. # side_or_rad и colour, которые можно передавать любому из классов.
  103. # В реальности же, добавив, например, треугольник, больше так не сделать, так как
  104. # он одним параметром не задаётся (разве что равнобедренный, но это отедльный
  105. # случай). Для этого я и сделал классовый метод generate_random(), который
  106. # уникален для каждой отдельной фигуры, и создаётся именно в классе,
  107. # а не где-то отдельно.
  108. figure = fig(side_or_rad, colour)
  109. figs.append(figure)
  110.  
  111. # Добавим ещё одну, воспользовавшись этим самым методом.
  112. fig = classes[random.randint(0, len(classes) - 1)]
  113. figs.append(fig.generate_random(COLOURS))
  114.  
  115.  
  116. # А теперь выведем _описание_ фигуры. По две строки на каждую, где первая - это
  117. # дефолтное питоновское описание любого объекта - класс и область в памяти,
  118. # а вторая - как раз наш метод, возвращающий текст с разрмерами и т.д.
  119. # (На самом деле первая строка это результат метода __repr__(), который в предыдущей версии
  120. # кода можешь увидеть.
  121. for fig in figs:
  122. print()
  123. print(fig)
  124. print(fig.description())
Success #stdin #stdout 0.03s 12360KB
stdin
Standard input is empty
stdout
Yellow square with side: 10.00, area: 100.00

<__main__.Diamond object at 0xb742276c>
Red diamond with side: 76.67, area: 5091.12

<__main__.Circle object at 0xb74227ac>
Cyan circle with radius: 11.41, area: 409.14

<__main__.Diamond object at 0xb74227ec>
Purple diamond with side: 22.19, area: 426.39

<__main__.Square object at 0xb742282c>
Cyan square with side: 78.03, area: 6088.35

<__main__.Diamond object at 0xb742286c>
Black diamond with side: 59.41, area: 3056.26

<__main__.Diamond object at 0xb74228ac>
Black diamond with side: 2.97, area: 7.63

<__main__.Circle object at 0xb74228ec>
Cyan circle with radius: 24.12, area: 1828.29

<__main__.Circle object at 0xb742292c>
Cyan circle with radius: 39.54, area: 4911.99

<__main__.Diamond object at 0xb742296c>
Yellow diamond with side: 44.68, area: 1728.80

<__main__.Square object at 0xb74229ac>
Black square with side: 81.36, area: 6618.77