1MATERIAL_DENSITIES = {
2 'Concrete': 2500,
3 'Brick': 2000,
4 'Stone': 1600,
5 'Wood': 600,
6 'Steel': 7700,
7}
8
9class Material:
10 def __init__(self, mass):
11 self.mass = mass
12 self._used = False
13
14 @property
15 def density(self):
16 return MATERIAL_DENSITIES[self.__class__.__name__]
17
18 @property
19 def volume(self):
20 return self.mass / self.density
21
22 def get_is_used(self):
23 return self._used
24
25
26class Concrete(Material):
27 pass
28
29
30class Brick(Material):
31 pass
32
33
34class Stone(Material):
35 pass
36
37
38class Wood(Material):
39 pass
40
41
42class Steel(Material):
43 pass
44
45
46class Factory:
47 _dynamic_classes = {}
48 _existing_factories = []
49
50 def __init__(self):
51 self.materials = []
52 Factory._existing_factories.append(self)
53
54 def __call__(self, *args, **kwargs):
55 if args and kwargs:
56 raise ValueError('Invalid operation: mix of positional and keyword arguments!')
57 if not args and not kwargs:
58 raise ValueError('Cannot create a factory without arguments!')
59
60 if args:
61 return self._create_composite_material(args)
62 if kwargs:
63 return self._create_materials_from_kwargs(kwargs)
64
65 def _create_composite_material(self, args):
66 material_types = []
67 for material in args:
68 if material._used:
69 raise AssertionError('Material already used!')
70 material._used = True
71 material_class = type(material)
72
73 if material_class in Factory._dynamic_classes.values():
74 separated = material_class.__name__.split('_')
75 for s in separated:
76 cls = globals()[s]
77 if cls not in material_types:
78 material_types.append(cls)
79 else:
80 if material_class not in material_types:
81 material_types.append(material_class)
82
83 for i in range(len(material_types) - 1):
84 for j in range(len(material_types) - i - 1):
85 if material_types[j].__name__ > material_types[j + 1].__name__:
86 material_types[j], material_types[j + 1] = material_types[j + 1], material_types[j]
87
88 composite_material = "_".join(cls.__name__ for cls in material_types)
89
90 if composite_material not in Factory._dynamic_classes:
91 total_density = 0
92 for cls in material_types:
93 total_density += MATERIAL_DENSITIES[cls.__name__]
94 average_density = total_density / len(material_types)
95
96 dynamic_material_class = type(composite_material, (Material,), {})
97 MATERIAL_DENSITIES[composite_material] = average_density
98 Factory._dynamic_classes[composite_material] = dynamic_material_class
99
100 composite_class = Factory._dynamic_classes[composite_material]
101 total_mass = sum(material.mass for material in args)
102 composite_material = composite_class(total_mass)
103 self.materials.append(composite_material)
104 return composite_material
105
106
107 def _create_materials_from_kwargs(self, kwargs):
108 created_materials = []
109 for material_name, mass in kwargs.items():
110 material_class = globals().get(material_name) or Factory._dynamic_classes.get(material_name)
111 if not material_class:
112 raise ValueError('Invalid material!')
113 material_instance = material_class(mass)
114 self.materials.append(material_instance)
115 created_materials.append(material_instance)
116 return tuple(created_materials)
117
118 def can_build(self, volume):
119 available_volume = sum(m.volume for m in self.materials if not m.get_is_used())
120 return available_volume >= volume
121
122 @classmethod
123 def can_build_together(cls, volume):
124 all_materials = [m for factory in cls._existing_factories for m in factory.materials]
125 total_volume = sum(m.volume for m in all_materials if not m.get_is_used())
126 return total_volume >= volume
.....F.F..
======================================================================
FAIL: test_positional_arguments_multiple_argument_from_initial_set (test.TestFactory.test_positional_arguments_multiple_argument_from_initial_set)
Test calling a factory using multiple positional arguments.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 116, in test_positional_arguments_multiple_argument_from_initial_set
concrete_wood = self.factory1(concrete, wood)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 61, in __call__
return self._create_composite_material(args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 69, in _create_composite_material
raise AssertionError('Material already used!')
AssertionError: Material already used!
======================================================================
FAIL: test_positional_arguments_single_argument (test.TestFactory.test_positional_arguments_single_argument)
Test calling a factory using a sigle positional argument.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 80, in test_positional_arguments_single_argument
self.assertIs(type(concrete2), solution.Concrete)
AssertionError: <class 'solution.Concrete'> is not <class 'solution.Concrete'>
----------------------------------------------------------------------
Ran 10 tests in 0.011s
FAILED (failures=2)
26.11.2024 16:02
26.11.2024 16:03
26.11.2024 16:07
26.11.2024 16:13
26.11.2024 16:20
26.11.2024 16:22
26.11.2024 16:23
26.11.2024 16:11