1class DoNothing:
2 """Represents a cool change for pass keyword."""
3
4 def __getattr__(self, _):
5 return self
6
7 def __call__(self, *args, **kwargs):
8 pass
9
10
11skip = DoNothing()
12
13
14class Material:
15 """Represents a parent class for materials."""
16
17 material_density_values = {
18 'Steel': 7700,
19 'Concrete': 2500,
20 'Brick': 2000,
21 'Stone': 1600,
22 'Wood': 600
23 }
24
25 def __init__(self, mass):
26 self.mass = mass
27 # works more dynamically
28 self.density = Material.material_density_values[self.__class__.__name__]
29 self.used = False
30
31 @property
32 def volume(self):
33 return self.mass / self.density
34
35
36class Brick(Material):
37 """Represents a class for a brick."""
38
39 skip
40
41
42class Concrete(Material):
43 """Represents a class for a concrete."""
44
45 skip()
46
47
48class Wood(Material):
49 """Represents a class for a wood."""
50
51 skip.skip
52
53
54class Stone(Material):
55 """Represents a class for a stone."""
56
57 skip
58
59
60class Steel(Material):
61 """Represents a class for a steel."""
62
63 skip
64
65
66class Factory:
67 """Represents a factory for creating materials and alloys."""
68
69 _created_classes = {
70 'Brick': Brick,
71 'Concrete': Concrete,
72 'Steel': Steel,
73 'Wood': Wood,
74 'Stone': Stone
75 }
76 _instances = []
77
78 def __init__(self):
79 self.created_materials = []
80 self._instances.append(self)
81
82 def __del__(self):
83 if self in self._instances:
84 self._instances.remove(self)
85
86 def __create_materials_from_named(self, kwargs):
87 return_tuple = ()
88 for key, value in kwargs.items():
89 if key not in self._created_classes:
90 raise ValueError(f'Invalid material class name: {key}')
91
92 material_class = self._created_classes[key]
93 material = material_class(value)
94 self._created_materials.add(material) # add to a set
95 self._all_created_materials.add(material) # add to a set with all
96 return_tuple += (material,)
97
98 return return_tuple
99
100 def __create_materials_from_positional(self, args):
101 class_types = [type(obj).__name__ for obj in args]
102 class_types = [cls for item in class_types for cls in item.split('_')]
103 sorted_class_types = sorted(class_types)
104 class_name = '_'.join(sorted_class_types)
105
106 if class_name in self._created_classes:
107 # mark all materials as used
108 [setattr(material, 'used', True) for material in args]
109 mass = sum(material.mass for material in args)
110 else:
111 density = 0
112 for material in args:
113 material.used = True
114 density += Material.material_density_values[type(material).__name__]
115
116 Material.material_density_values[str(class_name)] = density / len(args) # set the class density
117 new_material_class = type(str(class_name), (Material,), {}) # dynamic class
118 self._created_classes[class_name] = new_material_class # add a new class
119 mass = sum(material.mass for material in args)
120
121 return_material = self._created_classes[class_name](mass)
122 self._created_materials.add(return_material) # add to a set
123 self._all_created_materials.add(return_material) # add to a set with all
124 return return_material
125
126 def __call__(self, *args, **kwargs):
127 if not args and not kwargs:
128 raise ValueError('Factory cannot be called without arguments')
129 if args and kwargs:
130 raise ValueError('Factory cannot be called with both positional and named arguments')
131
132 if args: # positional
133 if any(material.used for material in args):
134 raise AssertionError('Cannot use already used material for alloy')
135
136 return self.__create_materials_from_positional(args)
137
138 if kwargs: # named
139 return self.__create_materials_from_named(kwargs)
140
141 def can_build(self, quantity):
142 volume = 0
143 for material in self._created_materials:
144 if material.used is False:
145 volume += material.volume
146
147 return volume >= quantity
148
149 @staticmethod
150 def can_build_together(quantity):
151 volume = 0
152 for material in Factory._all_created_materials:
153 if not material.used:
154 volume += material.volume
155
156 return volume >= quantity
.EEEEEEEE.
======================================================================
ERROR: test_can_build (test.TestFactory.test_can_build)
Test can_build methods.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 168, in test_can_build
concrete, steel = self.factory1(Concrete=2500, Steel=7700)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 139, in __call__
return self.__create_materials_from_named(kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 94, in __create_materials_from_named
self._created_materials.add(material) # add to a set
^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Factory' object has no attribute '_created_materials'. Did you mean: 'created_materials'?
======================================================================
ERROR: test_materials_between_factories (test.TestFactory.test_materials_between_factories)
Test materials sharing.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 153, in test_materials_between_factories
materials = self.factory1(Wood=1200, Concrete=5000, Brick=4000,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 139, in __call__
return self.__create_materials_from_named(kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 94, in __create_materials_from_named
self._created_materials.add(material) # add to a set
^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Factory' object has no attribute '_created_materials'. Did you mean: 'created_materials'?
======================================================================
ERROR: test_named_arguments (test.TestFactory.test_named_arguments)
Test calling a factory using named arguments.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 59, in test_named_arguments
result = self.factory1(Concrete=1)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 139, in __call__
return self.__create_materials_from_named(kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 94, in __create_materials_from_named
self._created_materials.add(material) # add to a set
^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Factory' object has no attribute '_created_materials'. Did you mean: 'created_materials'?
======================================================================
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 142, in test_named_arguments_with_dynamically_created_classes
materials = self.factory1(Wood=1200, Concrete=5000, Brick=4000,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 139, in __call__
return self.__create_materials_from_named(kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 94, in __create_materials_from_named
self._created_materials.add(material) # add to a set
^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Factory' object has no attribute '_created_materials'. Did you mean: 'created_materials'?
======================================================================
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 91, in test_positional_arguments_multiple_argument_from_initial_set
wood, concrete, brick = self.factory1(Wood=1200, Concrete=5000,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 139, in __call__
return self.__create_materials_from_named(kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 94, in __create_materials_from_named
self._created_materials.add(material) # add to a set
^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Factory' object has no attribute '_created_materials'. Did you mean: 'created_materials'?
======================================================================
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 123, in test_positional_arguments_multiple_argument_with_dynamics
materials = self.factory1(Stone=1600, Concrete=5000, Brick=4000)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 139, in __call__
return self.__create_materials_from_named(kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 94, in __create_materials_from_named
self._created_materials.add(material) # add to a set
^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Factory' object has no attribute '_created_materials'. Did you mean: 'created_materials'?
======================================================================
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 78, in test_positional_arguments_single_argument
concrete1, = self.factory1(Concrete=5000)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 139, in __call__
return self.__create_materials_from_named(kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 94, in __create_materials_from_named
self._created_materials.add(material) # add to a set
^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Factory' object has no attribute '_created_materials'. Did you mean: 'created_materials'?
======================================================================
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 134, in test_positional_arguments_singletons
materials1 = self.factory1(Wood=1200, Concrete=5000, Brick=4000)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 139, in __call__
return self.__create_materials_from_named(kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 94, in __create_materials_from_named
self._created_materials.add(material) # add to a set
^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Factory' object has no attribute '_created_materials'. Did you mean: 'created_materials'?
----------------------------------------------------------------------
Ran 10 tests in 0.015s
FAILED (errors=8)
Владимир Коцев
25.11.2024 18:25Дано така е по-добре. Благодаря за коментара.
|
Георги Кунчев
24.11.2024 13:26Можеш да напра иш `__del__`, който ще се извика при изтриване на инстанция. Намираш инстанцията по идентитет в списъка и я триеш.
|
Владимир Коцев
24.11.2024 12:44Не съм напълно сигурен как ще намеря правилна инстанция в статичния list _instances
|
Георги Кунчев
22.11.2024 10:47Един коментар, който оставям тук, защото не е случай, с който плануваме да тестваме, но си заслужава да се отбележи.
Поради факта, че държиш материали в инстанциите и в класа си, не покриваш случай, който в реалния свят е напълно валиден - дадена фабрика се срутва, съсипвайки всички създадени материали (разбирай `del some_factory`). При този случай не можеш да разбереш кои неща от `_all_created_materials` си изгубил и какво да изтриеш.
Ако вместо `_all_created_materials` пазиш иснтанциите на `Factory`, ще си ок:
```
class Factory:
_instances = []
def __init__(self):
self.created_materials = []
self._instances.append(self)
```
Мисля, че ти е ясно после как да ги обходиш, ама ако не е, питай.
|
f | 1 | class DoNothing: | f | 1 | class DoNothing: |
2 | """Represents a cool change for pass keyword.""" | 2 | """Represents a cool change for pass keyword.""" | ||
3 | 3 | ||||
4 | def __getattr__(self, _): | 4 | def __getattr__(self, _): | ||
5 | return self | 5 | return self | ||
6 | 6 | ||||
7 | def __call__(self, *args, **kwargs): | 7 | def __call__(self, *args, **kwargs): | ||
8 | pass | 8 | pass | ||
9 | 9 | ||||
10 | 10 | ||||
11 | skip = DoNothing() | 11 | skip = DoNothing() | ||
12 | 12 | ||||
13 | 13 | ||||
14 | class Material: | 14 | class Material: | ||
15 | """Represents a parent class for materials.""" | 15 | """Represents a parent class for materials.""" | ||
16 | 16 | ||||
17 | material_density_values = { | 17 | material_density_values = { | ||
18 | 'Steel': 7700, | 18 | 'Steel': 7700, | ||
19 | 'Concrete': 2500, | 19 | 'Concrete': 2500, | ||
20 | 'Brick': 2000, | 20 | 'Brick': 2000, | ||
21 | 'Stone': 1600, | 21 | 'Stone': 1600, | ||
22 | 'Wood': 600 | 22 | 'Wood': 600 | ||
23 | } | 23 | } | ||
24 | 24 | ||||
25 | def __init__(self, mass): | 25 | def __init__(self, mass): | ||
26 | self.mass = mass | 26 | self.mass = mass | ||
27 | # works more dynamically | 27 | # works more dynamically | ||
28 | self.density = Material.material_density_values[self.__class__.__name__] | 28 | self.density = Material.material_density_values[self.__class__.__name__] | ||
29 | self.used = False | 29 | self.used = False | ||
30 | 30 | ||||
31 | @property | 31 | @property | ||
32 | def volume(self): | 32 | def volume(self): | ||
33 | return self.mass / self.density | 33 | return self.mass / self.density | ||
34 | 34 | ||||
35 | 35 | ||||
36 | class Brick(Material): | 36 | class Brick(Material): | ||
37 | """Represents a class for a brick.""" | 37 | """Represents a class for a brick.""" | ||
38 | 38 | ||||
39 | skip | 39 | skip | ||
40 | 40 | ||||
41 | 41 | ||||
42 | class Concrete(Material): | 42 | class Concrete(Material): | ||
43 | """Represents a class for a concrete.""" | 43 | """Represents a class for a concrete.""" | ||
44 | 44 | ||||
45 | skip() | 45 | skip() | ||
46 | 46 | ||||
47 | 47 | ||||
48 | class Wood(Material): | 48 | class Wood(Material): | ||
49 | """Represents a class for a wood.""" | 49 | """Represents a class for a wood.""" | ||
50 | 50 | ||||
51 | skip.skip | 51 | skip.skip | ||
52 | 52 | ||||
53 | 53 | ||||
54 | class Stone(Material): | 54 | class Stone(Material): | ||
55 | """Represents a class for a stone.""" | 55 | """Represents a class for a stone.""" | ||
56 | 56 | ||||
57 | skip | 57 | skip | ||
58 | 58 | ||||
59 | 59 | ||||
60 | class Steel(Material): | 60 | class Steel(Material): | ||
61 | """Represents a class for a steel.""" | 61 | """Represents a class for a steel.""" | ||
62 | 62 | ||||
63 | skip | 63 | skip | ||
64 | 64 | ||||
65 | 65 | ||||
66 | class Factory: | 66 | class Factory: | ||
67 | """Represents a factory for creating materials and alloys.""" | 67 | """Represents a factory for creating materials and alloys.""" | ||
68 | 68 | ||||
69 | _created_classes = { | 69 | _created_classes = { | ||
70 | 'Brick': Brick, | 70 | 'Brick': Brick, | ||
71 | 'Concrete': Concrete, | 71 | 'Concrete': Concrete, | ||
72 | 'Steel': Steel, | 72 | 'Steel': Steel, | ||
73 | 'Wood': Wood, | 73 | 'Wood': Wood, | ||
74 | 'Stone': Stone | 74 | 'Stone': Stone | ||
75 | } | 75 | } | ||
76 | _instances = [] | 76 | _instances = [] | ||
77 | 77 | ||||
78 | def __init__(self): | 78 | def __init__(self): | ||
79 | self.created_materials = [] | 79 | self.created_materials = [] | ||
80 | self._instances.append(self) | 80 | self._instances.append(self) | ||
81 | 81 | ||||
82 | def __del__(self): | 82 | def __del__(self): | ||
t | 83 | if self in self.instances: | t | 83 | if self in self._instances: |
84 | self.instances.remove(self) | 84 | self._instances.remove(self) | ||
85 | 85 | ||||
86 | def __create_materials_from_named(self, kwargs): | 86 | def __create_materials_from_named(self, kwargs): | ||
87 | return_tuple = () | 87 | return_tuple = () | ||
88 | for key, value in kwargs.items(): | 88 | for key, value in kwargs.items(): | ||
89 | if key not in self._created_classes: | 89 | if key not in self._created_classes: | ||
90 | raise ValueError(f'Invalid material class name: {key}') | 90 | raise ValueError(f'Invalid material class name: {key}') | ||
91 | 91 | ||||
92 | material_class = self._created_classes[key] | 92 | material_class = self._created_classes[key] | ||
93 | material = material_class(value) | 93 | material = material_class(value) | ||
94 | self._created_materials.add(material) # add to a set | 94 | self._created_materials.add(material) # add to a set | ||
95 | self._all_created_materials.add(material) # add to a set with all | 95 | self._all_created_materials.add(material) # add to a set with all | ||
96 | return_tuple += (material,) | 96 | return_tuple += (material,) | ||
97 | 97 | ||||
98 | return return_tuple | 98 | return return_tuple | ||
99 | 99 | ||||
100 | def __create_materials_from_positional(self, args): | 100 | def __create_materials_from_positional(self, args): | ||
101 | class_types = [type(obj).__name__ for obj in args] | 101 | class_types = [type(obj).__name__ for obj in args] | ||
102 | class_types = [cls for item in class_types for cls in item.split('_')] | 102 | class_types = [cls for item in class_types for cls in item.split('_')] | ||
103 | sorted_class_types = sorted(class_types) | 103 | sorted_class_types = sorted(class_types) | ||
104 | class_name = '_'.join(sorted_class_types) | 104 | class_name = '_'.join(sorted_class_types) | ||
105 | 105 | ||||
106 | if class_name in self._created_classes: | 106 | if class_name in self._created_classes: | ||
107 | # mark all materials as used | 107 | # mark all materials as used | ||
108 | [setattr(material, 'used', True) for material in args] | 108 | [setattr(material, 'used', True) for material in args] | ||
109 | mass = sum(material.mass for material in args) | 109 | mass = sum(material.mass for material in args) | ||
110 | else: | 110 | else: | ||
111 | density = 0 | 111 | density = 0 | ||
112 | for material in args: | 112 | for material in args: | ||
113 | material.used = True | 113 | material.used = True | ||
114 | density += Material.material_density_values[type(material).__name__] | 114 | density += Material.material_density_values[type(material).__name__] | ||
115 | 115 | ||||
116 | Material.material_density_values[str(class_name)] = density / len(args) # set the class density | 116 | Material.material_density_values[str(class_name)] = density / len(args) # set the class density | ||
117 | new_material_class = type(str(class_name), (Material,), {}) # dynamic class | 117 | new_material_class = type(str(class_name), (Material,), {}) # dynamic class | ||
118 | self._created_classes[class_name] = new_material_class # add a new class | 118 | self._created_classes[class_name] = new_material_class # add a new class | ||
119 | mass = sum(material.mass for material in args) | 119 | mass = sum(material.mass for material in args) | ||
120 | 120 | ||||
121 | return_material = self._created_classes[class_name](mass) | 121 | return_material = self._created_classes[class_name](mass) | ||
122 | self._created_materials.add(return_material) # add to a set | 122 | self._created_materials.add(return_material) # add to a set | ||
123 | self._all_created_materials.add(return_material) # add to a set with all | 123 | self._all_created_materials.add(return_material) # add to a set with all | ||
124 | return return_material | 124 | return return_material | ||
125 | 125 | ||||
126 | def __call__(self, *args, **kwargs): | 126 | def __call__(self, *args, **kwargs): | ||
127 | if not args and not kwargs: | 127 | if not args and not kwargs: | ||
128 | raise ValueError('Factory cannot be called without arguments') | 128 | raise ValueError('Factory cannot be called without arguments') | ||
129 | if args and kwargs: | 129 | if args and kwargs: | ||
130 | raise ValueError('Factory cannot be called with both positional and named arguments') | 130 | raise ValueError('Factory cannot be called with both positional and named arguments') | ||
131 | 131 | ||||
132 | if args: # positional | 132 | if args: # positional | ||
133 | if any(material.used for material in args): | 133 | if any(material.used for material in args): | ||
134 | raise AssertionError('Cannot use already used material for alloy') | 134 | raise AssertionError('Cannot use already used material for alloy') | ||
135 | 135 | ||||
136 | return self.__create_materials_from_positional(args) | 136 | return self.__create_materials_from_positional(args) | ||
137 | 137 | ||||
138 | if kwargs: # named | 138 | if kwargs: # named | ||
139 | return self.__create_materials_from_named(kwargs) | 139 | return self.__create_materials_from_named(kwargs) | ||
140 | 140 | ||||
141 | def can_build(self, quantity): | 141 | def can_build(self, quantity): | ||
142 | volume = 0 | 142 | volume = 0 | ||
143 | for material in self._created_materials: | 143 | for material in self._created_materials: | ||
144 | if material.used is False: | 144 | if material.used is False: | ||
145 | volume += material.volume | 145 | volume += material.volume | ||
146 | 146 | ||||
147 | return volume >= quantity | 147 | return volume >= quantity | ||
148 | 148 | ||||
149 | @staticmethod | 149 | @staticmethod | ||
150 | def can_build_together(quantity): | 150 | def can_build_together(quantity): | ||
151 | volume = 0 | 151 | volume = 0 | ||
152 | for material in Factory._all_created_materials: | 152 | for material in Factory._all_created_materials: | ||
153 | if not material.used: | 153 | if not material.used: | ||
154 | volume += material.volume | 154 | volume += material.volume | ||
155 | 155 | ||||
156 | return volume >= quantity | 156 | return volume >= quantity |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | class DoNothing: | f | 1 | class DoNothing: |
2 | """Represents a cool change for pass keyword.""" | 2 | """Represents a cool change for pass keyword.""" | ||
3 | 3 | ||||
4 | def __getattr__(self, _): | 4 | def __getattr__(self, _): | ||
5 | return self | 5 | return self | ||
6 | 6 | ||||
7 | def __call__(self, *args, **kwargs): | 7 | def __call__(self, *args, **kwargs): | ||
8 | pass | 8 | pass | ||
9 | 9 | ||||
10 | 10 | ||||
11 | skip = DoNothing() | 11 | skip = DoNothing() | ||
12 | 12 | ||||
13 | 13 | ||||
14 | class Material: | 14 | class Material: | ||
15 | """Represents a parent class for materials.""" | 15 | """Represents a parent class for materials.""" | ||
16 | 16 | ||||
17 | material_density_values = { | 17 | material_density_values = { | ||
18 | 'Steel': 7700, | 18 | 'Steel': 7700, | ||
19 | 'Concrete': 2500, | 19 | 'Concrete': 2500, | ||
20 | 'Brick': 2000, | 20 | 'Brick': 2000, | ||
21 | 'Stone': 1600, | 21 | 'Stone': 1600, | ||
22 | 'Wood': 600 | 22 | 'Wood': 600 | ||
23 | } | 23 | } | ||
24 | 24 | ||||
25 | def __init__(self, mass): | 25 | def __init__(self, mass): | ||
26 | self.mass = mass | 26 | self.mass = mass | ||
27 | # works more dynamically | 27 | # works more dynamically | ||
28 | self.density = Material.material_density_values[self.__class__.__name__] | 28 | self.density = Material.material_density_values[self.__class__.__name__] | ||
29 | self.used = False | 29 | self.used = False | ||
30 | 30 | ||||
31 | @property | 31 | @property | ||
32 | def volume(self): | 32 | def volume(self): | ||
33 | return self.mass / self.density | 33 | return self.mass / self.density | ||
34 | 34 | ||||
35 | 35 | ||||
36 | class Brick(Material): | 36 | class Brick(Material): | ||
37 | """Represents a class for a brick.""" | 37 | """Represents a class for a brick.""" | ||
38 | 38 | ||||
39 | skip | 39 | skip | ||
40 | 40 | ||||
41 | 41 | ||||
42 | class Concrete(Material): | 42 | class Concrete(Material): | ||
43 | """Represents a class for a concrete.""" | 43 | """Represents a class for a concrete.""" | ||
44 | 44 | ||||
45 | skip() | 45 | skip() | ||
46 | 46 | ||||
47 | 47 | ||||
48 | class Wood(Material): | 48 | class Wood(Material): | ||
49 | """Represents a class for a wood.""" | 49 | """Represents a class for a wood.""" | ||
50 | 50 | ||||
51 | skip.skip | 51 | skip.skip | ||
52 | 52 | ||||
53 | 53 | ||||
54 | class Stone(Material): | 54 | class Stone(Material): | ||
55 | """Represents a class for a stone.""" | 55 | """Represents a class for a stone.""" | ||
56 | 56 | ||||
57 | skip | 57 | skip | ||
58 | 58 | ||||
59 | 59 | ||||
60 | class Steel(Material): | 60 | class Steel(Material): | ||
61 | """Represents a class for a steel.""" | 61 | """Represents a class for a steel.""" | ||
62 | 62 | ||||
63 | skip | 63 | skip | ||
64 | 64 | ||||
65 | 65 | ||||
66 | class Factory: | 66 | class Factory: | ||
67 | """Represents a factory for creating materials and alloys.""" | 67 | """Represents a factory for creating materials and alloys.""" | ||
68 | 68 | ||||
69 | _created_classes = { | 69 | _created_classes = { | ||
70 | 'Brick': Brick, | 70 | 'Brick': Brick, | ||
71 | 'Concrete': Concrete, | 71 | 'Concrete': Concrete, | ||
72 | 'Steel': Steel, | 72 | 'Steel': Steel, | ||
73 | 'Wood': Wood, | 73 | 'Wood': Wood, | ||
74 | 'Stone': Stone | 74 | 'Stone': Stone | ||
75 | } | 75 | } | ||
n | 76 | _all_created_materials = set() | n | 76 | _instances = [] |
77 | 77 | ||||
78 | def __init__(self): | 78 | def __init__(self): | ||
t | 79 | self._created_materials = set() | t | 79 | self.created_materials = [] |
80 | self._instances.append(self) | ||||
81 | |||||
82 | def __del__(self): | ||||
83 | if self in self.instances: | ||||
84 | self.instances.remove(self) | ||||
80 | 85 | ||||
81 | def __create_materials_from_named(self, kwargs): | 86 | def __create_materials_from_named(self, kwargs): | ||
82 | return_tuple = () | 87 | return_tuple = () | ||
83 | for key, value in kwargs.items(): | 88 | for key, value in kwargs.items(): | ||
84 | if key not in self._created_classes: | 89 | if key not in self._created_classes: | ||
85 | raise ValueError(f'Invalid material class name: {key}') | 90 | raise ValueError(f'Invalid material class name: {key}') | ||
86 | 91 | ||||
87 | material_class = self._created_classes[key] | 92 | material_class = self._created_classes[key] | ||
88 | material = material_class(value) | 93 | material = material_class(value) | ||
89 | self._created_materials.add(material) # add to a set | 94 | self._created_materials.add(material) # add to a set | ||
90 | self._all_created_materials.add(material) # add to a set with all | 95 | self._all_created_materials.add(material) # add to a set with all | ||
91 | return_tuple += (material,) | 96 | return_tuple += (material,) | ||
92 | 97 | ||||
93 | return return_tuple | 98 | return return_tuple | ||
94 | 99 | ||||
95 | def __create_materials_from_positional(self, args): | 100 | def __create_materials_from_positional(self, args): | ||
96 | class_types = [type(obj).__name__ for obj in args] | 101 | class_types = [type(obj).__name__ for obj in args] | ||
97 | class_types = [cls for item in class_types for cls in item.split('_')] | 102 | class_types = [cls for item in class_types for cls in item.split('_')] | ||
98 | sorted_class_types = sorted(class_types) | 103 | sorted_class_types = sorted(class_types) | ||
99 | class_name = '_'.join(sorted_class_types) | 104 | class_name = '_'.join(sorted_class_types) | ||
100 | 105 | ||||
101 | if class_name in self._created_classes: | 106 | if class_name in self._created_classes: | ||
102 | # mark all materials as used | 107 | # mark all materials as used | ||
103 | [setattr(material, 'used', True) for material in args] | 108 | [setattr(material, 'used', True) for material in args] | ||
104 | mass = sum(material.mass for material in args) | 109 | mass = sum(material.mass for material in args) | ||
105 | else: | 110 | else: | ||
106 | density = 0 | 111 | density = 0 | ||
107 | for material in args: | 112 | for material in args: | ||
108 | material.used = True | 113 | material.used = True | ||
109 | density += Material.material_density_values[type(material).__name__] | 114 | density += Material.material_density_values[type(material).__name__] | ||
110 | 115 | ||||
111 | Material.material_density_values[str(class_name)] = density / len(args) # set the class density | 116 | Material.material_density_values[str(class_name)] = density / len(args) # set the class density | ||
112 | new_material_class = type(str(class_name), (Material,), {}) # dynamic class | 117 | new_material_class = type(str(class_name), (Material,), {}) # dynamic class | ||
113 | self._created_classes[class_name] = new_material_class # add a new class | 118 | self._created_classes[class_name] = new_material_class # add a new class | ||
114 | mass = sum(material.mass for material in args) | 119 | mass = sum(material.mass for material in args) | ||
115 | 120 | ||||
116 | return_material = self._created_classes[class_name](mass) | 121 | return_material = self._created_classes[class_name](mass) | ||
117 | self._created_materials.add(return_material) # add to a set | 122 | self._created_materials.add(return_material) # add to a set | ||
118 | self._all_created_materials.add(return_material) # add to a set with all | 123 | self._all_created_materials.add(return_material) # add to a set with all | ||
119 | return return_material | 124 | return return_material | ||
120 | 125 | ||||
121 | def __call__(self, *args, **kwargs): | 126 | def __call__(self, *args, **kwargs): | ||
122 | if not args and not kwargs: | 127 | if not args and not kwargs: | ||
123 | raise ValueError('Factory cannot be called without arguments') | 128 | raise ValueError('Factory cannot be called without arguments') | ||
124 | if args and kwargs: | 129 | if args and kwargs: | ||
125 | raise ValueError('Factory cannot be called with both positional and named arguments') | 130 | raise ValueError('Factory cannot be called with both positional and named arguments') | ||
126 | 131 | ||||
127 | if args: # positional | 132 | if args: # positional | ||
128 | if any(material.used for material in args): | 133 | if any(material.used for material in args): | ||
129 | raise AssertionError('Cannot use already used material for alloy') | 134 | raise AssertionError('Cannot use already used material for alloy') | ||
130 | 135 | ||||
131 | return self.__create_materials_from_positional(args) | 136 | return self.__create_materials_from_positional(args) | ||
132 | 137 | ||||
133 | if kwargs: # named | 138 | if kwargs: # named | ||
134 | return self.__create_materials_from_named(kwargs) | 139 | return self.__create_materials_from_named(kwargs) | ||
135 | 140 | ||||
136 | def can_build(self, quantity): | 141 | def can_build(self, quantity): | ||
137 | volume = 0 | 142 | volume = 0 | ||
138 | for material in self._created_materials: | 143 | for material in self._created_materials: | ||
139 | if material.used is False: | 144 | if material.used is False: | ||
140 | volume += material.volume | 145 | volume += material.volume | ||
141 | 146 | ||||
142 | return volume >= quantity | 147 | return volume >= quantity | ||
143 | 148 | ||||
144 | @staticmethod | 149 | @staticmethod | ||
145 | def can_build_together(quantity): | 150 | def can_build_together(quantity): | ||
146 | volume = 0 | 151 | volume = 0 | ||
147 | for material in Factory._all_created_materials: | 152 | for material in Factory._all_created_materials: | ||
148 | if not material.used: | 153 | if not material.used: | ||
149 | volume += material.volume | 154 | volume += material.volume | ||
150 | 155 | ||||
151 | return volume >= quantity | 156 | return volume >= quantity |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | class DoNothing: | f | 1 | class DoNothing: |
2 | """Represents a cool change for pass keyword.""" | 2 | """Represents a cool change for pass keyword.""" | ||
3 | 3 | ||||
4 | def __getattr__(self, _): | 4 | def __getattr__(self, _): | ||
5 | return self | 5 | return self | ||
6 | 6 | ||||
7 | def __call__(self, *args, **kwargs): | 7 | def __call__(self, *args, **kwargs): | ||
8 | pass | 8 | pass | ||
9 | 9 | ||||
10 | 10 | ||||
11 | skip = DoNothing() | 11 | skip = DoNothing() | ||
12 | 12 | ||||
13 | 13 | ||||
14 | class Material: | 14 | class Material: | ||
15 | """Represents a parent class for materials.""" | 15 | """Represents a parent class for materials.""" | ||
16 | 16 | ||||
17 | material_density_values = { | 17 | material_density_values = { | ||
18 | 'Steel': 7700, | 18 | 'Steel': 7700, | ||
19 | 'Concrete': 2500, | 19 | 'Concrete': 2500, | ||
20 | 'Brick': 2000, | 20 | 'Brick': 2000, | ||
21 | 'Stone': 1600, | 21 | 'Stone': 1600, | ||
22 | 'Wood': 600 | 22 | 'Wood': 600 | ||
23 | } | 23 | } | ||
24 | 24 | ||||
25 | def __init__(self, mass): | 25 | def __init__(self, mass): | ||
26 | self.mass = mass | 26 | self.mass = mass | ||
27 | # works more dynamically | 27 | # works more dynamically | ||
28 | self.density = Material.material_density_values[self.__class__.__name__] | 28 | self.density = Material.material_density_values[self.__class__.__name__] | ||
29 | self.used = False | 29 | self.used = False | ||
30 | 30 | ||||
31 | @property | 31 | @property | ||
32 | def volume(self): | 32 | def volume(self): | ||
33 | return self.mass / self.density | 33 | return self.mass / self.density | ||
34 | 34 | ||||
35 | 35 | ||||
36 | class Brick(Material): | 36 | class Brick(Material): | ||
37 | """Represents a class for a brick.""" | 37 | """Represents a class for a brick.""" | ||
38 | 38 | ||||
39 | skip | 39 | skip | ||
40 | 40 | ||||
41 | 41 | ||||
42 | class Concrete(Material): | 42 | class Concrete(Material): | ||
43 | """Represents a class for a concrete.""" | 43 | """Represents a class for a concrete.""" | ||
44 | 44 | ||||
45 | skip() | 45 | skip() | ||
46 | 46 | ||||
47 | 47 | ||||
48 | class Wood(Material): | 48 | class Wood(Material): | ||
49 | """Represents a class for a wood.""" | 49 | """Represents a class for a wood.""" | ||
50 | 50 | ||||
51 | skip.skip | 51 | skip.skip | ||
52 | 52 | ||||
53 | 53 | ||||
54 | class Stone(Material): | 54 | class Stone(Material): | ||
55 | """Represents a class for a stone.""" | 55 | """Represents a class for a stone.""" | ||
56 | 56 | ||||
57 | skip | 57 | skip | ||
58 | 58 | ||||
59 | 59 | ||||
60 | class Steel(Material): | 60 | class Steel(Material): | ||
61 | """Represents a class for a steel.""" | 61 | """Represents a class for a steel.""" | ||
62 | 62 | ||||
63 | skip | 63 | skip | ||
64 | 64 | ||||
65 | 65 | ||||
66 | class Factory: | 66 | class Factory: | ||
67 | """Represents a factory for creating materials and alloys.""" | 67 | """Represents a factory for creating materials and alloys.""" | ||
68 | 68 | ||||
69 | _created_classes = { | 69 | _created_classes = { | ||
70 | 'Brick': Brick, | 70 | 'Brick': Brick, | ||
71 | 'Concrete': Concrete, | 71 | 'Concrete': Concrete, | ||
72 | 'Steel': Steel, | 72 | 'Steel': Steel, | ||
73 | 'Wood': Wood, | 73 | 'Wood': Wood, | ||
74 | 'Stone': Stone | 74 | 'Stone': Stone | ||
75 | } | 75 | } | ||
76 | _all_created_materials = set() | 76 | _all_created_materials = set() | ||
77 | 77 | ||||
78 | def __init__(self): | 78 | def __init__(self): | ||
79 | self._created_materials = set() | 79 | self._created_materials = set() | ||
80 | 80 | ||||
81 | def __create_materials_from_named(self, kwargs): | 81 | def __create_materials_from_named(self, kwargs): | ||
82 | return_tuple = () | 82 | return_tuple = () | ||
83 | for key, value in kwargs.items(): | 83 | for key, value in kwargs.items(): | ||
n | 84 | if key in self._created_classes: | n | 84 | if key not in self._created_classes: |
85 | material_class = self._created_classes[key] | ||||
86 | material = material_class(value) | ||||
87 | self._created_materials.add(material) # add to a set | ||||
88 | Factory._all_created_materials.add(material) # add to a set with all | ||||
89 | return_tuple += (material,) | ||||
90 | else: | ||||
91 | raise ValueError(f'Invalid material class name: {key}') | 85 | raise ValueError(f'Invalid material class name: {key}') | ||
n | n | 86 | |||
87 | material_class = self._created_classes[key] | ||||
88 | material = material_class(value) | ||||
89 | self._created_materials.add(material) # add to a set | ||||
90 | self._all_created_materials.add(material) # add to a set with all | ||||
91 | return_tuple += (material,) | ||||
92 | 92 | ||||
93 | return return_tuple | 93 | return return_tuple | ||
94 | 94 | ||||
95 | def __create_materials_from_positional(self, args): | 95 | def __create_materials_from_positional(self, args): | ||
96 | class_types = [type(obj).__name__ for obj in args] | 96 | class_types = [type(obj).__name__ for obj in args] | ||
97 | class_types = [cls for item in class_types for cls in item.split('_')] | 97 | class_types = [cls for item in class_types for cls in item.split('_')] | ||
98 | sorted_class_types = sorted(class_types) | 98 | sorted_class_types = sorted(class_types) | ||
99 | class_name = '_'.join(sorted_class_types) | 99 | class_name = '_'.join(sorted_class_types) | ||
100 | 100 | ||||
n | 101 | if class_name in self._created_classes.keys(): | n | 101 | if class_name in self._created_classes: |
102 | # mark all materials as used | 102 | # mark all materials as used | ||
103 | [setattr(material, 'used', True) for material in args] | 103 | [setattr(material, 'used', True) for material in args] | ||
n | 104 | material_class = self._created_classes[class_name] | n | ||
105 | mass = sum(material.mass for material in args) | 104 | mass = sum(material.mass for material in args) | ||
n | 106 | return_material = material_class(mass) | n | ||
107 | self._created_materials.add(return_material) # add to a set | ||||
108 | self._all_created_materials.add(return_material) # add to a set with all | ||||
109 | return return_material | ||||
110 | else: | 105 | else: | ||
111 | density = 0 | 106 | density = 0 | ||
112 | for material in args: | 107 | for material in args: | ||
113 | material.used = True | 108 | material.used = True | ||
n | 114 | density += Material.material_density_values[str(type(material).__name__)] | n | 109 | density += Material.material_density_values[type(material).__name__] |
115 | 110 | ||||
116 | Material.material_density_values[str(class_name)] = density / len(args) # set the class density | 111 | Material.material_density_values[str(class_name)] = density / len(args) # set the class density | ||
117 | new_material_class = type(str(class_name), (Material,), {}) # dynamic class | 112 | new_material_class = type(str(class_name), (Material,), {}) # dynamic class | ||
n | 118 | n | |||
119 | self._created_classes[class_name] = new_material_class # add a new class | 113 | self._created_classes[class_name] = new_material_class # add a new class | ||
120 | mass = sum(material.mass for material in args) | 114 | mass = sum(material.mass for material in args) | ||
n | 121 | return_material = new_material_class(mass) | n | 115 | |
116 | return_material = self._created_classes[class_name](mass) | ||||
122 | self._created_materials.add(return_material) # add to a set | 117 | self._created_materials.add(return_material) # add to a set | ||
123 | Factory._all_created_materials.add(return_material) # add to a set with all | 118 | self._all_created_materials.add(return_material) # add to a set with all | ||
124 | return return_material | 119 | return return_material | ||
125 | 120 | ||||
126 | def __call__(self, *args, **kwargs): | 121 | def __call__(self, *args, **kwargs): | ||
127 | if not args and not kwargs: | 122 | if not args and not kwargs: | ||
128 | raise ValueError('Factory cannot be called without arguments') | 123 | raise ValueError('Factory cannot be called without arguments') | ||
129 | if args and kwargs: | 124 | if args and kwargs: | ||
130 | raise ValueError('Factory cannot be called with both positional and named arguments') | 125 | raise ValueError('Factory cannot be called with both positional and named arguments') | ||
131 | 126 | ||||
132 | if args: # positional | 127 | if args: # positional | ||
133 | if any(material.used for material in args): | 128 | if any(material.used for material in args): | ||
134 | raise AssertionError('Cannot use already used material for alloy') | 129 | raise AssertionError('Cannot use already used material for alloy') | ||
135 | 130 | ||||
136 | return self.__create_materials_from_positional(args) | 131 | return self.__create_materials_from_positional(args) | ||
137 | 132 | ||||
138 | if kwargs: # named | 133 | if kwargs: # named | ||
139 | return self.__create_materials_from_named(kwargs) | 134 | return self.__create_materials_from_named(kwargs) | ||
140 | 135 | ||||
141 | def can_build(self, quantity): | 136 | def can_build(self, quantity): | ||
142 | volume = 0 | 137 | volume = 0 | ||
143 | for material in self._created_materials: | 138 | for material in self._created_materials: | ||
144 | if material.used is False: | 139 | if material.used is False: | ||
145 | volume += material.volume | 140 | volume += material.volume | ||
146 | 141 | ||||
147 | return volume >= quantity | 142 | return volume >= quantity | ||
148 | 143 | ||||
149 | @staticmethod | 144 | @staticmethod | ||
150 | def can_build_together(quantity): | 145 | def can_build_together(quantity): | ||
151 | volume = 0 | 146 | volume = 0 | ||
152 | for material in Factory._all_created_materials: | 147 | for material in Factory._all_created_materials: | ||
n | 153 | if material.used is False: | n | 148 | if not material.used: |
154 | volume += material.volume | 149 | volume += material.volume | ||
155 | 150 | ||||
156 | return volume >= quantity | 151 | return volume >= quantity | ||
t | 157 | t | |||
158 | factory1 = Factory() | ||||
159 | factory2 = Factory() | ||||
160 | wood1, steel1, brick1, stone1, concrete1 = factory1(Wood=5, Steel=15, Brick=60, Stone=300, Concrete=20) | ||||
161 | wood2, steel2, brick2, stone2, concrete2 = factory2(Wood=5, Steel=30, Brick=300, Stone=600, Concrete=2000) | ||||
162 | |||||
163 | result1 = factory1(wood1, brick1) | ||||
164 | result2 = factory2(concrete2, stone1) | ||||
165 | result = factory1(result1, result2) | ||||
166 | print(result.__class__.__name__) |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
t | 1 | class DoNothing: | t | 1 | class DoNothing: |
2 | """Represents a cool change for pass keyword.""" | 2 | """Represents a cool change for pass keyword.""" | ||
3 | 3 | ||||
4 | def __getattr__(self, _): | 4 | def __getattr__(self, _): | ||
5 | return self | 5 | return self | ||
6 | 6 | ||||
7 | def __call__(self, *args, **kwargs): | 7 | def __call__(self, *args, **kwargs): | ||
8 | pass | 8 | pass | ||
9 | 9 | ||||
10 | 10 | ||||
11 | skip = DoNothing() | 11 | skip = DoNothing() | ||
12 | 12 | ||||
13 | 13 | ||||
14 | class Material: | 14 | class Material: | ||
15 | """Represents a parent class for materials.""" | 15 | """Represents a parent class for materials.""" | ||
16 | 16 | ||||
17 | material_density_values = { | 17 | material_density_values = { | ||
18 | 'Steel': 7700, | 18 | 'Steel': 7700, | ||
19 | 'Concrete': 2500, | 19 | 'Concrete': 2500, | ||
20 | 'Brick': 2000, | 20 | 'Brick': 2000, | ||
21 | 'Stone': 1600, | 21 | 'Stone': 1600, | ||
22 | 'Wood': 600 | 22 | 'Wood': 600 | ||
23 | } | 23 | } | ||
24 | 24 | ||||
25 | def __init__(self, mass): | 25 | def __init__(self, mass): | ||
26 | self.mass = mass | 26 | self.mass = mass | ||
27 | # works more dynamically | 27 | # works more dynamically | ||
28 | self.density = Material.material_density_values[self.__class__.__name__] | 28 | self.density = Material.material_density_values[self.__class__.__name__] | ||
29 | self.used = False | 29 | self.used = False | ||
30 | 30 | ||||
31 | @property | 31 | @property | ||
32 | def volume(self): | 32 | def volume(self): | ||
33 | return self.mass / self.density | 33 | return self.mass / self.density | ||
34 | 34 | ||||
35 | 35 | ||||
36 | class Brick(Material): | 36 | class Brick(Material): | ||
37 | """Represents a class for a brick.""" | 37 | """Represents a class for a brick.""" | ||
38 | 38 | ||||
39 | skip | 39 | skip | ||
40 | 40 | ||||
41 | 41 | ||||
42 | class Concrete(Material): | 42 | class Concrete(Material): | ||
43 | """Represents a class for a concrete.""" | 43 | """Represents a class for a concrete.""" | ||
44 | 44 | ||||
45 | skip() | 45 | skip() | ||
46 | 46 | ||||
47 | 47 | ||||
48 | class Wood(Material): | 48 | class Wood(Material): | ||
49 | """Represents a class for a wood.""" | 49 | """Represents a class for a wood.""" | ||
50 | 50 | ||||
51 | skip.skip | 51 | skip.skip | ||
52 | 52 | ||||
53 | 53 | ||||
54 | class Stone(Material): | 54 | class Stone(Material): | ||
55 | """Represents a class for a stone.""" | 55 | """Represents a class for a stone.""" | ||
56 | 56 | ||||
57 | skip | 57 | skip | ||
58 | 58 | ||||
59 | 59 | ||||
60 | class Steel(Material): | 60 | class Steel(Material): | ||
61 | """Represents a class for a steel.""" | 61 | """Represents a class for a steel.""" | ||
62 | 62 | ||||
63 | skip | 63 | skip | ||
64 | 64 | ||||
65 | 65 | ||||
66 | class Factory: | 66 | class Factory: | ||
67 | """Represents a factory for creating materials and alloys.""" | 67 | """Represents a factory for creating materials and alloys.""" | ||
68 | 68 | ||||
69 | _created_classes = { | 69 | _created_classes = { | ||
70 | 'Brick': Brick, | 70 | 'Brick': Brick, | ||
71 | 'Concrete': Concrete, | 71 | 'Concrete': Concrete, | ||
72 | 'Steel': Steel, | 72 | 'Steel': Steel, | ||
73 | 'Wood': Wood, | 73 | 'Wood': Wood, | ||
74 | 'Stone': Stone | 74 | 'Stone': Stone | ||
75 | } | 75 | } | ||
76 | _all_created_materials = set() | 76 | _all_created_materials = set() | ||
77 | 77 | ||||
78 | def __init__(self): | 78 | def __init__(self): | ||
79 | self._created_materials = set() | 79 | self._created_materials = set() | ||
80 | 80 | ||||
81 | def __create_materials_from_named(self, kwargs): | 81 | def __create_materials_from_named(self, kwargs): | ||
82 | return_tuple = () | 82 | return_tuple = () | ||
83 | for key, value in kwargs.items(): | 83 | for key, value in kwargs.items(): | ||
84 | if key in self._created_classes: | 84 | if key in self._created_classes: | ||
85 | material_class = self._created_classes[key] | 85 | material_class = self._created_classes[key] | ||
86 | material = material_class(value) | 86 | material = material_class(value) | ||
87 | self._created_materials.add(material) # add to a set | 87 | self._created_materials.add(material) # add to a set | ||
88 | Factory._all_created_materials.add(material) # add to a set with all | 88 | Factory._all_created_materials.add(material) # add to a set with all | ||
89 | return_tuple += (material,) | 89 | return_tuple += (material,) | ||
90 | else: | 90 | else: | ||
91 | raise ValueError(f'Invalid material class name: {key}') | 91 | raise ValueError(f'Invalid material class name: {key}') | ||
92 | 92 | ||||
93 | return return_tuple | 93 | return return_tuple | ||
94 | 94 | ||||
95 | def __create_materials_from_positional(self, args): | 95 | def __create_materials_from_positional(self, args): | ||
96 | class_types = [type(obj).__name__ for obj in args] | 96 | class_types = [type(obj).__name__ for obj in args] | ||
97 | class_types = [cls for item in class_types for cls in item.split('_')] | 97 | class_types = [cls for item in class_types for cls in item.split('_')] | ||
98 | sorted_class_types = sorted(class_types) | 98 | sorted_class_types = sorted(class_types) | ||
99 | class_name = '_'.join(sorted_class_types) | 99 | class_name = '_'.join(sorted_class_types) | ||
100 | 100 | ||||
101 | if class_name in self._created_classes.keys(): | 101 | if class_name in self._created_classes.keys(): | ||
102 | # mark all materials as used | 102 | # mark all materials as used | ||
103 | [setattr(material, 'used', True) for material in args] | 103 | [setattr(material, 'used', True) for material in args] | ||
104 | material_class = self._created_classes[class_name] | 104 | material_class = self._created_classes[class_name] | ||
105 | mass = sum(material.mass for material in args) | 105 | mass = sum(material.mass for material in args) | ||
106 | return_material = material_class(mass) | 106 | return_material = material_class(mass) | ||
107 | self._created_materials.add(return_material) # add to a set | 107 | self._created_materials.add(return_material) # add to a set | ||
108 | self._all_created_materials.add(return_material) # add to a set with all | 108 | self._all_created_materials.add(return_material) # add to a set with all | ||
109 | return return_material | 109 | return return_material | ||
110 | else: | 110 | else: | ||
111 | density = 0 | 111 | density = 0 | ||
112 | for material in args: | 112 | for material in args: | ||
113 | material.used = True | 113 | material.used = True | ||
114 | density += Material.material_density_values[str(type(material).__name__)] | 114 | density += Material.material_density_values[str(type(material).__name__)] | ||
115 | 115 | ||||
116 | Material.material_density_values[str(class_name)] = density / len(args) # set the class density | 116 | Material.material_density_values[str(class_name)] = density / len(args) # set the class density | ||
117 | new_material_class = type(str(class_name), (Material,), {}) # dynamic class | 117 | new_material_class = type(str(class_name), (Material,), {}) # dynamic class | ||
118 | 118 | ||||
119 | self._created_classes[class_name] = new_material_class # add a new class | 119 | self._created_classes[class_name] = new_material_class # add a new class | ||
120 | mass = sum(material.mass for material in args) | 120 | mass = sum(material.mass for material in args) | ||
121 | return_material = new_material_class(mass) | 121 | return_material = new_material_class(mass) | ||
122 | self._created_materials.add(return_material) # add to a set | 122 | self._created_materials.add(return_material) # add to a set | ||
123 | Factory._all_created_materials.add(return_material) # add to a set with all | 123 | Factory._all_created_materials.add(return_material) # add to a set with all | ||
124 | return return_material | 124 | return return_material | ||
125 | 125 | ||||
126 | def __call__(self, *args, **kwargs): | 126 | def __call__(self, *args, **kwargs): | ||
127 | if not args and not kwargs: | 127 | if not args and not kwargs: | ||
128 | raise ValueError('Factory cannot be called without arguments') | 128 | raise ValueError('Factory cannot be called without arguments') | ||
129 | if args and kwargs: | 129 | if args and kwargs: | ||
130 | raise ValueError('Factory cannot be called with both positional and named arguments') | 130 | raise ValueError('Factory cannot be called with both positional and named arguments') | ||
131 | 131 | ||||
132 | if args: # positional | 132 | if args: # positional | ||
133 | if any(material.used for material in args): | 133 | if any(material.used for material in args): | ||
134 | raise AssertionError('Cannot use already used material for alloy') | 134 | raise AssertionError('Cannot use already used material for alloy') | ||
135 | 135 | ||||
136 | return self.__create_materials_from_positional(args) | 136 | return self.__create_materials_from_positional(args) | ||
137 | 137 | ||||
138 | if kwargs: # named | 138 | if kwargs: # named | ||
139 | return self.__create_materials_from_named(kwargs) | 139 | return self.__create_materials_from_named(kwargs) | ||
140 | 140 | ||||
141 | def can_build(self, quantity): | 141 | def can_build(self, quantity): | ||
142 | volume = 0 | 142 | volume = 0 | ||
143 | for material in self._created_materials: | 143 | for material in self._created_materials: | ||
144 | if material.used is False: | 144 | if material.used is False: | ||
145 | volume += material.volume | 145 | volume += material.volume | ||
146 | 146 | ||||
147 | return volume >= quantity | 147 | return volume >= quantity | ||
148 | 148 | ||||
149 | @staticmethod | 149 | @staticmethod | ||
150 | def can_build_together(quantity): | 150 | def can_build_together(quantity): | ||
151 | volume = 0 | 151 | volume = 0 | ||
152 | for material in Factory._all_created_materials: | 152 | for material in Factory._all_created_materials: | ||
153 | if material.used is False: | 153 | if material.used is False: | ||
154 | volume += material.volume | 154 | volume += material.volume | ||
155 | 155 | ||||
156 | return volume >= quantity | 156 | return volume >= quantity | ||
157 | 157 | ||||
158 | factory1 = Factory() | 158 | factory1 = Factory() | ||
159 | factory2 = Factory() | 159 | factory2 = Factory() | ||
160 | wood1, steel1, brick1, stone1, concrete1 = factory1(Wood=5, Steel=15, Brick=60, Stone=300, Concrete=20) | 160 | wood1, steel1, brick1, stone1, concrete1 = factory1(Wood=5, Steel=15, Brick=60, Stone=300, Concrete=20) | ||
161 | wood2, steel2, brick2, stone2, concrete2 = factory2(Wood=5, Steel=30, Brick=300, Stone=600, Concrete=2000) | 161 | wood2, steel2, brick2, stone2, concrete2 = factory2(Wood=5, Steel=30, Brick=300, Stone=600, Concrete=2000) | ||
162 | 162 | ||||
163 | result1 = factory1(wood1, brick1) | 163 | result1 = factory1(wood1, brick1) | ||
164 | result2 = factory2(concrete2, stone1) | 164 | result2 = factory2(concrete2, stone1) | ||
165 | result = factory1(result1, result2) | 165 | result = factory1(result1, result2) | ||
166 | print(result.__class__.__name__) | 166 | print(result.__class__.__name__) |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | class DoNothing: | f | 1 | class DoNothing: |
n | n | 2 | """Represents a cool change for pass keyword.""" | ||
3 | |||||
2 | def __getattr__(self, _): | 4 | def __getattr__(self, _): | ||
3 | return self | 5 | return self | ||
n | n | 6 | |||
4 | def __call__(self, *args, **kwargs): | 7 | def __call__(self, *args, **kwargs): | ||
5 | pass | 8 | pass | ||
6 | 9 | ||||
n | n | 10 | |||
7 | skip = DoNothing() | 11 | skip = DoNothing() | ||
n | n | 12 | |||
8 | 13 | ||||
9 | class Material: | 14 | class Material: | ||
10 | """Represents a parent class for materials.""" | 15 | """Represents a parent class for materials.""" | ||
11 | 16 | ||||
12 | material_density_values = { | 17 | material_density_values = { | ||
13 | 'Steel': 7700, | 18 | 'Steel': 7700, | ||
14 | 'Concrete': 2500, | 19 | 'Concrete': 2500, | ||
15 | 'Brick': 2000, | 20 | 'Brick': 2000, | ||
16 | 'Stone': 1600, | 21 | 'Stone': 1600, | ||
17 | 'Wood': 600 | 22 | 'Wood': 600 | ||
18 | } | 23 | } | ||
19 | 24 | ||||
20 | def __init__(self, mass): | 25 | def __init__(self, mass): | ||
21 | self.mass = mass | 26 | self.mass = mass | ||
n | n | 27 | # works more dynamically | ||
22 | self.density = Material.material_density_values[self.__class__.__name__] # works more dynamically | 28 | self.density = Material.material_density_values[self.__class__.__name__] | ||
23 | self.used = False | 29 | self.used = False | ||
24 | 30 | ||||
25 | @property | 31 | @property | ||
26 | def volume(self): | 32 | def volume(self): | ||
27 | return self.mass / self.density | 33 | return self.mass / self.density | ||
28 | 34 | ||||
n | n | 35 | |||
29 | class Brick(Material): | 36 | class Brick(Material): | ||
30 | """Represents a class for a brick.""" | 37 | """Represents a class for a brick.""" | ||
n | n | 38 | |||
31 | skip | 39 | skip | ||
n | n | 40 | |||
32 | 41 | ||||
33 | class Concrete(Material): | 42 | class Concrete(Material): | ||
34 | """Represents a class for a concrete.""" | 43 | """Represents a class for a concrete.""" | ||
n | n | 44 | |||
35 | skip() | 45 | skip() | ||
n | n | 46 | |||
36 | 47 | ||||
37 | class Wood(Material): | 48 | class Wood(Material): | ||
38 | """Represents a class for a wood.""" | 49 | """Represents a class for a wood.""" | ||
n | n | 50 | |||
39 | skip.skip | 51 | skip.skip | ||
n | n | 52 | |||
40 | 53 | ||||
41 | class Stone(Material): | 54 | class Stone(Material): | ||
42 | """Represents a class for a stone.""" | 55 | """Represents a class for a stone.""" | ||
n | n | 56 | |||
43 | skip | 57 | skip | ||
n | n | 58 | |||
44 | 59 | ||||
45 | class Steel(Material): | 60 | class Steel(Material): | ||
46 | """Represents a class for a steel.""" | 61 | """Represents a class for a steel.""" | ||
n | n | 62 | |||
47 | skip | 63 | skip | ||
n | n | 64 | |||
48 | 65 | ||||
49 | class Factory: | 66 | class Factory: | ||
50 | """Represents a factory for creating materials and alloys.""" | 67 | """Represents a factory for creating materials and alloys.""" | ||
51 | 68 | ||||
52 | _created_classes = { | 69 | _created_classes = { | ||
53 | 'Brick': Brick, | 70 | 'Brick': Brick, | ||
54 | 'Concrete': Concrete, | 71 | 'Concrete': Concrete, | ||
55 | 'Steel': Steel, | 72 | 'Steel': Steel, | ||
56 | 'Wood': Wood, | 73 | 'Wood': Wood, | ||
57 | 'Stone': Stone | 74 | 'Stone': Stone | ||
58 | } | 75 | } | ||
59 | _all_created_materials = set() | 76 | _all_created_materials = set() | ||
60 | 77 | ||||
61 | def __init__(self): | 78 | def __init__(self): | ||
62 | self._created_materials = set() | 79 | self._created_materials = set() | ||
63 | 80 | ||||
64 | def __create_materials_from_named(self, kwargs): | 81 | def __create_materials_from_named(self, kwargs): | ||
65 | return_tuple = () | 82 | return_tuple = () | ||
66 | for key, value in kwargs.items(): | 83 | for key, value in kwargs.items(): | ||
67 | if key in self._created_classes: | 84 | if key in self._created_classes: | ||
68 | material_class = self._created_classes[key] | 85 | material_class = self._created_classes[key] | ||
69 | material = material_class(value) | 86 | material = material_class(value) | ||
n | 70 | self._created_materials.add(material) # add to a set | n | 87 | self._created_materials.add(material) # add to a set |
71 | Factory._all_created_materials.add(material) # add to a set with all | 88 | Factory._all_created_materials.add(material) # add to a set with all | ||
72 | return_tuple += (material,) | 89 | return_tuple += (material,) | ||
73 | else: | 90 | else: | ||
74 | raise ValueError(f'Invalid material class name: {key}') | 91 | raise ValueError(f'Invalid material class name: {key}') | ||
75 | 92 | ||||
76 | return return_tuple | 93 | return return_tuple | ||
77 | 94 | ||||
78 | def __create_materials_from_positional(self, args): | 95 | def __create_materials_from_positional(self, args): | ||
79 | class_types = [type(obj).__name__ for obj in args] | 96 | class_types = [type(obj).__name__ for obj in args] | ||
80 | class_types = [cls for item in class_types for cls in item.split('_')] | 97 | class_types = [cls for item in class_types for cls in item.split('_')] | ||
81 | sorted_class_types = sorted(class_types) | 98 | sorted_class_types = sorted(class_types) | ||
82 | class_name = '_'.join(sorted_class_types) | 99 | class_name = '_'.join(sorted_class_types) | ||
83 | 100 | ||||
84 | if class_name in self._created_classes.keys(): | 101 | if class_name in self._created_classes.keys(): | ||
n | n | 102 | # mark all materials as used | ||
85 | [setattr(material, 'used', True) for material in args] # mark all materials as used | 103 | [setattr(material, 'used', True) for material in args] | ||
86 | material_class = self._created_classes[class_name] | 104 | material_class = self._created_classes[class_name] | ||
n | 87 | return_material = material_class(sum(material.mass for material in args)) | n | 105 | mass = sum(material.mass for material in args) |
106 | return_material = material_class(mass) | ||||
88 | self._created_materials.add(return_material) # add to a set | 107 | self._created_materials.add(return_material) # add to a set | ||
89 | self._all_created_materials.add(return_material) # add to a set with all | 108 | self._all_created_materials.add(return_material) # add to a set with all | ||
90 | return return_material | 109 | return return_material | ||
91 | else: | 110 | else: | ||
92 | density = 0 | 111 | density = 0 | ||
93 | for material in args: | 112 | for material in args: | ||
94 | material.used = True | 113 | material.used = True | ||
95 | density += Material.material_density_values[str(type(material).__name__)] | 114 | density += Material.material_density_values[str(type(material).__name__)] | ||
96 | 115 | ||||
97 | Material.material_density_values[str(class_name)] = density / len(args) # set the class density | 116 | Material.material_density_values[str(class_name)] = density / len(args) # set the class density | ||
98 | new_material_class = type(str(class_name), (Material,), {}) # dynamic class | 117 | new_material_class = type(str(class_name), (Material,), {}) # dynamic class | ||
99 | 118 | ||||
100 | self._created_classes[class_name] = new_material_class # add a new class | 119 | self._created_classes[class_name] = new_material_class # add a new class | ||
n | n | 120 | mass = sum(material.mass for material in args) | ||
101 | return_material = new_material_class(sum(material.mass for material in args)) | 121 | return_material = new_material_class(mass) | ||
102 | self._created_materials.add(return_material) # add to a set | 122 | self._created_materials.add(return_material) # add to a set | ||
103 | Factory._all_created_materials.add(return_material) # add to a set with all | 123 | Factory._all_created_materials.add(return_material) # add to a set with all | ||
104 | return return_material | 124 | return return_material | ||
105 | 125 | ||||
106 | def __call__(self, *args, **kwargs): | 126 | def __call__(self, *args, **kwargs): | ||
107 | if not args and not kwargs: | 127 | if not args and not kwargs: | ||
108 | raise ValueError('Factory cannot be called without arguments') | 128 | raise ValueError('Factory cannot be called without arguments') | ||
109 | if args and kwargs: | 129 | if args and kwargs: | ||
110 | raise ValueError('Factory cannot be called with both positional and named arguments') | 130 | raise ValueError('Factory cannot be called with both positional and named arguments') | ||
111 | 131 | ||||
n | 112 | if args: # positional | n | 132 | if args: # positional |
113 | if any(material.used for material in args): | 133 | if any(material.used for material in args): | ||
114 | raise AssertionError('Cannot use already used material for alloy') | 134 | raise AssertionError('Cannot use already used material for alloy') | ||
115 | 135 | ||||
116 | return self.__create_materials_from_positional(args) | 136 | return self.__create_materials_from_positional(args) | ||
117 | 137 | ||||
t | 118 | if kwargs: # named | t | 138 | if kwargs: # named |
119 | return self.__create_materials_from_named(kwargs) | 139 | return self.__create_materials_from_named(kwargs) | ||
120 | 140 | ||||
121 | def can_build(self, quantity): | 141 | def can_build(self, quantity): | ||
122 | volume = 0 | 142 | volume = 0 | ||
123 | for material in self._created_materials: | 143 | for material in self._created_materials: | ||
124 | if material.used is False: | 144 | if material.used is False: | ||
125 | volume += material.volume | 145 | volume += material.volume | ||
126 | 146 | ||||
127 | return volume >= quantity | 147 | return volume >= quantity | ||
128 | 148 | ||||
129 | @staticmethod | 149 | @staticmethod | ||
130 | def can_build_together(quantity): | 150 | def can_build_together(quantity): | ||
131 | volume = 0 | 151 | volume = 0 | ||
132 | for material in Factory._all_created_materials: | 152 | for material in Factory._all_created_materials: | ||
133 | if material.used is False: | 153 | if material.used is False: | ||
134 | volume += material.volume | 154 | volume += material.volume | ||
135 | 155 | ||||
136 | return volume >= quantity | 156 | return volume >= quantity | ||
137 | 157 | ||||
138 | factory1 = Factory() | 158 | factory1 = Factory() | ||
139 | factory2 = Factory() | 159 | factory2 = Factory() | ||
140 | wood1, steel1, brick1, stone1, concrete1 = factory1(Wood=5, Steel=15, Brick=60, Stone=300, Concrete=20) | 160 | wood1, steel1, brick1, stone1, concrete1 = factory1(Wood=5, Steel=15, Brick=60, Stone=300, Concrete=20) | ||
141 | wood2, steel2, brick2, stone2, concrete2 = factory2(Wood=5, Steel=30, Brick=300, Stone=600, Concrete=2000) | 161 | wood2, steel2, brick2, stone2, concrete2 = factory2(Wood=5, Steel=30, Brick=300, Stone=600, Concrete=2000) | ||
142 | 162 | ||||
143 | result1 = factory1(wood1, brick1) | 163 | result1 = factory1(wood1, brick1) | ||
144 | result2 = factory2(concrete2, stone1) | 164 | result2 = factory2(concrete2, stone1) | ||
145 | result = factory1(result1, result2) | 165 | result = factory1(result1, result2) | ||
146 | print(result.__class__.__name__) | 166 | print(result.__class__.__name__) |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|