1class Material:
2 """Parent class for defining a material."""
3
4 _DENSITY = 1
5 made_of = None
6
7 def __init__(self, mass):
8 self.mass = mass
9 self.is_valid = True
10
11 @property
12 def volume(self):
13 return self.mass / self._DENSITY
14
15 def invalidate(self):
16 self.is_valid = False
17
18
19class Concrete(Material):
20 """Define the material concrete."""
21
22 _DENSITY = 2500
23 made_of = ("Concrete",)
24
25
26class Brick(Material):
27 """Define the material brick."""
28
29 _DENSITY = 2000
30 made_of = ("Brick",)
31
32
33class Stone(Material):
34 """Define the material stone."""
35
36 _DENSITY = 1600
37 made_of = ("Stone",)
38
39
40class Wood(Material):
41 """Define the material wood."""
42
43 _DENSITY = 600
44 made_of = ("Wood",)
45
46
47class Steel(Material):
48 """Define the material steel."""
49
50 _DENSITY = 7700
51 made_of = ("Steel",)
52
53
54class Factory:
55 """Factory for material production."""
56
57 allowed_materials = {
58 "Concrete": Concrete,
59 "Brick": Brick,
60 "Stone": Stone,
61 "Wood": Wood,
62 "Steel": Steel
63 }
64
65 all_created_materials = []
66
67 def __init__(self):
68 self.created_materials = []
69
70 def __call__(self, *args, **kwargs):
71 if args and kwargs:
72 raise ValueError("Both arguments and keyword arguments cannot be provided.")
73
74 if not args and not kwargs:
75 raise ValueError("What are you trying to do without materials?!")
76
77 if kwargs:
78 try:
79 materials = tuple(
80 self.allowed_materials[name](mass) for name, mass in kwargs.items()
81 )
82 self.created_materials.extend(list(materials))
83 Factory.all_created_materials.extend(list(materials))
84 except KeyError:
85 raise ValueError("Material not found!")
86 return materials
87
88 if args:
89 if not all(isinstance(arg, tuple(self.allowed_materials.values()))
90 for arg in args):
91 raise ValueError("All arguments must be instances of existing materials.")
92 if not all(arg.is_valid for arg in args):
93 raise AssertionError("All materials must be unused.")
94
95 for arg in args:
96 arg.invalidate()
97
98 material_names = set()
99 for arg in args:
100 material_names.update(type(arg).made_of)
101 material_names_inorder = sorted(list(material_names))
102 class_name = "_".join(material_names_inorder)
103
104 if class_name in Factory.allowed_materials:
105 alloy_class = Factory.allowed_materials[class_name]
106 else:
107 densities = [self.allowed_materials[name]._DENSITY
108 for name in material_names]
109 avg_density = sum(densities) / len(densities)
110 class_attributes = {
111 'made_of': tuple(material_names),
112 '_DENSITY': avg_density
113 }
114 alloy_class = type(class_name, (Material,), class_attributes)
115 Factory.allowed_materials[class_name] = alloy_class
116
117 new_material = alloy_class(sum(arg.mass for arg in args))
118 self.created_materials.append(new_material)
119 Factory.all_created_materials.append(new_material)
120 return new_material
121
122 def can_build(self, volume):
123 """Check if enough valid materials have been created to build a wall."""
124 total_volume = sum(material.volume for material in self.created_materials
125 if material.is_valid)
126 return total_volume >= volume
127
128 @classmethod
129 def can_build_together(cls, volume):
130 """Check if enough valid materials have been created across all factories."""
131 total_volume = sum(material.volume for material in cls.all_created_materials
132 if material.is_valid)
133 return total_volume >= volume
..........
----------------------------------------------------------------------
Ran 10 tests in 0.014s
OK
Виктор Бечев
23.11.2024 22:46Останалото е доста чисто, браво.
|
Виктор Бечев
23.11.2024 22:25Що се отнася до 79-те символа - ние самите сме една идея по-либерални в собствения си код. Стремим се към 79 като генерално правило, защото нерядко води до чисто написан код и ни кара да се замисляме дали не пишем нечетими глупости. Но както в PEP8 пише "A Foolish Consistency is the Hobgoblin of Little Minds", така че ако кодът ще е по-четим с някой друг ред из него, който е 90 или 104 символа - so be it.
Що се отнася до разделението по файлове - в този случай не бих казал, че е необходимо. Обхватът на заданието е прекалено малък за да има смисъл. Разделението по файлове следва да става на базата на логически обособени парчета код, както например по време на уъркшопа - entities.py беше файл, в който изсипвахме функционалността, main.py беше файл, в който седеше "енджина", който принтираше по терминала и взимаше вход. При допълнително усложняване на дизайна - различни атаки, магии и прочие - може би би било да разделим различните елементи в различни файлове. За съжаление няма едно правило, по което можем да се водим за всеки проект, така че "логически обособени части" е най-доброто, което мога да ти предложа. С други думи - да нямаме функционалност за генериране на произволни числа, заедно с функционалност за рисуване по екрана, но пък прекаленото раздробяване също не е необходимо _(откъдето всъщност тръгна и въпросът)_.
|
Марина Господинова
23.11.2024 17:14Понеже този път се опитах да спазвам повече PEP8, имам въпрос за правилото за 79 символа на ред. Когато изписваме съобщение и то ли трябва да се пренася, дори да е едно цяло изречение, и като цяло има ли изключения за надвишаването на този брой символи?
И още нещо - ако можехме да качваме отделни файлове тук (както и за проекта), добра идея ли е базовите класове да бяха отделени в друг файл (за повече четимост, например в проекти по ООП на C++ трябваше абсолютно всеки клас да е разделен в отделен файл)?
|
23.11.2024 22:30
23.11.2024 22:32