1class Material:
2 def __init__(self, mass):
3 self.mass = mass
4
5 @property
6 def density(self) -> float:
7 return 1
8
9 @property
10 def volume(self) -> float:
11 if self.density == 0:
12 return float('inf') #to make sure no zero division will happen
13 return self.mass / self.density
14
15
16class Concrete(Material):
17 @property
18 def density(self):
19 return 2500
20
21class Brick(Material):
22 @property
23 def density(self):
24 return 2000
25
26class Stone(Material):
27 @property
28 def density(self):
29 return 1600
30
31class Wood(Material):
32 @property
33 def density(self):
34 return 600
35
36class Steel(Material):
37 @property
38 def density(self):
39 return 7700
40
41class Factory:
42 already_existing = {}
43 produced = []
44
45 def __call__(self, *args, **kwargs):
46 if not args and not kwargs:
47 raise ValueError("Should pass some arguments!")
48
49 if args and kwargs:
50 raise ValueError("Can't pass both positional and keyword arguments!")
51
52 if args:
53 return self.handle_args(args)
54 if kwargs:
55 return self.handle_kwargs(kwargs)
56
57 def handle_kwargs(self, kwargs):
58 materials = []
59 for name, mass in kwargs.items():
60 material_class = globals().get(name)
61 if material_class is None or not issubclass(material_class, Material):
62 raise ValueError("Invalid material")
63 material = material_class(mass)
64 materials.append(material)
65
66 self.produced.extend(materials)
67 return tuple(materials)
68
69 def handle_args(self, args):
70 classes = {type(arg) for arg in args}
71 for each_object in args:
72 if not isinstance(each_object, Material):
73 raise ValueError("Invalid object!")
74 if hasattr(each_object, "_used") and each_object._used:
75 raise AssertionError("Material has already been used!")
76
77 each_object._used = True #mark it as used
78
79 composite_name = "_".join(sorted(cls.__name__ for cls in classes))
80 if composite_name in self.already_existing:
81 composite_class = self.already_existing[composite_name]
82 else:
83 densities = [cls.density for cls in classes]
84 composite_density = sum(densities) / len(densities)
85
86 #this is how we create a dynamic class, tova ne znaeh, che se pravi taka
87 composite_class = type(composite_name,(Material,),{"density": composite_density},)
88 self.already_existing[composite_name] = composite_class
89
90 mass_in_total = sum(each_obj.mass for each_obj in args)
91 composite = composite_class(mass_in_total)
92 self.produced.append(composite)
93 return composite
94
95 def can_build(self, required_volume: float):
96 unused_materials = [material for material in self.produced if not getattr(material, "_used", False)]
97
98 if not unused_materials:
99 return False
100
101 total_volume = sum(material.volume for material in unused_materials)
102
103 return total_volume >= required_volume
104
105 @classmethod
106 def can_build_together(cls, required_volume: float):
107
108 unused_materials = [
109 material for factory in cls.already_existing.values()
110 for material in factory.produced if not getattr(material, "_used", False)
111 ]
112
113 if not unused_materials:
114 return False
115
116 total_volume = sum(material.volume for material in unused_materials)
117
118 return total_volume >= required_volume
.EE.EEEEE.
======================================================================
ERROR: test_can_build (test.TestFactory.test_can_build)
Test can_build methods.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 172, in test_can_build
brick_wood = self.factory2(brick, wood)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 53, in __call__
return self.handle_args(args)
^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 84, in handle_args
composite_density = sum(densities) / len(densities)
^^^^^^^^^^^^^^
TypeError: unsupported operand type(s) for +: 'int' and 'property'
======================================================================
ERROR: test_materials_between_factories (test.TestFactory.test_materials_between_factories)
Test materials sharing.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 155, in test_materials_between_factories
result1 = self.factory1(*materials)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 53, in __call__
return self.handle_args(args)
^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 84, in handle_args
composite_density = sum(densities) / len(densities)
^^^^^^^^^^^^^^
TypeError: unsupported operand type(s) for +: 'int' and 'property'
======================================================================
ERROR: test_named_arguments_with_dynamically_created_classes (test.TestFactory.test_named_arguments_with_dynamically_created_classes)
Test dynamically created classes uniqueness.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 144, in test_named_arguments_with_dynamically_created_classes
result1 = self.factory1(*materials)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 53, in __call__
return self.handle_args(args)
^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 84, in handle_args
composite_density = sum(densities) / len(densities)
^^^^^^^^^^^^^^
TypeError: unsupported operand type(s) for +: 'int' and 'property'
======================================================================
ERROR: 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 93, in test_positional_arguments_multiple_argument_from_initial_set
result = self.factory1(wood, brick, concrete)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 53, in __call__
return self.handle_args(args)
^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 84, in handle_args
composite_density = sum(densities) / len(densities)
^^^^^^^^^^^^^^
TypeError: unsupported operand type(s) for +: 'int' and 'property'
======================================================================
ERROR: test_positional_arguments_multiple_argument_with_dynamics (test.TestFactory.test_positional_arguments_multiple_argument_with_dynamics)
Test calling a factory using multiple positional arguments.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 124, in test_positional_arguments_multiple_argument_with_dynamics
brick_concrete_stone = self.factory1(*materials)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 53, in __call__
return self.handle_args(args)
^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 84, in handle_args
composite_density = sum(densities) / len(densities)
^^^^^^^^^^^^^^
TypeError: unsupported operand type(s) for +: 'int' and 'property'
======================================================================
ERROR: 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 79, in test_positional_arguments_single_argument
concrete2 = self.factory1(concrete1)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 53, in __call__
return self.handle_args(args)
^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 84, in handle_args
composite_density = sum(densities) / len(densities)
^^^^^^^^^^^^^^
TypeError: unsupported operand type(s) for +: 'int' and 'property'
======================================================================
ERROR: test_positional_arguments_singletons (test.TestFactory.test_positional_arguments_singletons)
Test dynamically created classes uniqueness.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 135, in test_positional_arguments_singletons
brick_concrete_wood1 = self.factory1(*materials1)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 53, in __call__
return self.handle_args(args)
^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 84, in handle_args
composite_density = sum(densities) / len(densities)
^^^^^^^^^^^^^^
TypeError: unsupported operand type(s) for +: 'int' and 'property'
----------------------------------------------------------------------
Ran 10 tests in 0.038s
FAILED (errors=7)
26.11.2024 16:40
26.11.2024 16:40
26.11.2024 16:43
26.11.2024 16:45
26.11.2024 16:39
26.11.2024 16:38