Домашни > Another brick in the wall > Решения > Решението на Владимир Коцев

Резултати
2 точки от тестове
0 точки от учител

2 точки общо

2 успешни теста
8 неуспешни теста
Код

  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) ``` Мисля, че ти е ясно после как да ги обходиш, ама ако не е, питай.
История

f1class DoNothing:f1class DoNothing:
2    """Represents a cool change for pass keyword."""2    """Represents a cool change for pass keyword."""
33
4    def __getattr__(self, _):4    def __getattr__(self, _):
5        return self5        return self
66
7    def __call__(self, *args, **kwargs):7    def __call__(self, *args, **kwargs):
8        pass8        pass
99
1010
11skip = DoNothing()11skip = DoNothing()
1212
1313
14class Material:14class Material:
15    """Represents a parent class for materials."""15    """Represents a parent class for materials."""
1616
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': 60022        'Wood': 600
23    }23    }
2424
25    def __init__(self, mass):25    def __init__(self, mass):
26        self.mass = mass26        self.mass = mass
27        # works more dynamically27        # 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 = False29        self.used = False
3030
31    @property31    @property
32    def volume(self):32    def volume(self):
33        return self.mass / self.density33        return self.mass / self.density
3434
3535
36class Brick(Material):36class Brick(Material):
37    """Represents a class for a brick."""37    """Represents a class for a brick."""
3838
39    skip39    skip
4040
4141
42class Concrete(Material):42class Concrete(Material):
43    """Represents a class for a concrete."""43    """Represents a class for a concrete."""
4444
45    skip()45    skip()
4646
4747
48class Wood(Material):48class Wood(Material):
49    """Represents a class for a wood."""49    """Represents a class for a wood."""
5050
51    skip.skip51    skip.skip
5252
5353
54class Stone(Material):54class Stone(Material):
55    """Represents a class for a stone."""55    """Represents a class for a stone."""
5656
57    skip57    skip
5858
5959
60class Steel(Material):60class Steel(Material):
61    """Represents a class for a steel."""61    """Represents a class for a steel."""
6262
63    skip63    skip
6464
6565
66class Factory:66class Factory:
67    """Represents a factory for creating materials and alloys."""67    """Represents a factory for creating materials and alloys."""
6868
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': Stone74        'Stone': Stone
75    }75    }
76    _instances = []76    _instances = []
7777
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)
8181
82    def __del__(self):82    def __del__(self):
t83        if self in self.instances:t83        if self in self._instances:
84            self.instances.remove(self)84            self._instances.remove(self)
8585
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}')
9191
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 set94            self._created_materials.add(material)  # add to a set
95            self._all_created_materials.add(material)  # add to a set with all95            self._all_created_materials.add(material)  # add to a set with all
96            return_tuple += (material,)96            return_tuple += (material,)
9797
98        return return_tuple98        return return_tuple
9999
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)
105105
106        if class_name in self._created_classes:106        if class_name in self._created_classes:
107            # mark all materials as used107            # 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 = 0111            density = 0
112            for material in args:112            for material in args:
113                material.used = True113                material.used = True
114                density += Material.material_density_values[type(material).__name__]114                density += Material.material_density_values[type(material).__name__]
115115
116            Material.material_density_values[str(class_name)] = density / len(args)  # set the class density116            Material.material_density_values[str(class_name)] = density / len(args)  # set the class density
117            new_material_class = type(str(class_name), (Material,), {})  # dynamic class117            new_material_class = type(str(class_name), (Material,), {})  # dynamic class
118            self._created_classes[class_name] = new_material_class  # add a new class118            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)
120120
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 set122        self._created_materials.add(return_material)  # add to a set
123        self._all_created_materials.add(return_material)  # add to a set with all123        self._all_created_materials.add(return_material)  # add to a set with all
124        return return_material124        return return_material
125125
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')
131131
132        if args:  # positional132        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')
135135
136            return self.__create_materials_from_positional(args)136            return self.__create_materials_from_positional(args)
137137
138        if kwargs:  # named138        if kwargs:  # named
139            return self.__create_materials_from_named(kwargs)139            return self.__create_materials_from_named(kwargs)
140140
141    def can_build(self, quantity):141    def can_build(self, quantity):
142        volume = 0142        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.volume145                volume += material.volume
146146
147        return volume >= quantity147        return volume >= quantity
148148
149    @staticmethod149    @staticmethod
150    def can_build_together(quantity):150    def can_build_together(quantity):
151        volume = 0151        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.volume154                volume += material.volume
155155
156        return volume >= quantity156        return volume >= quantity
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1class DoNothing:f1class DoNothing:
2    """Represents a cool change for pass keyword."""2    """Represents a cool change for pass keyword."""
33
4    def __getattr__(self, _):4    def __getattr__(self, _):
5        return self5        return self
66
7    def __call__(self, *args, **kwargs):7    def __call__(self, *args, **kwargs):
8        pass8        pass
99
1010
11skip = DoNothing()11skip = DoNothing()
1212
1313
14class Material:14class Material:
15    """Represents a parent class for materials."""15    """Represents a parent class for materials."""
1616
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': 60022        'Wood': 600
23    }23    }
2424
25    def __init__(self, mass):25    def __init__(self, mass):
26        self.mass = mass26        self.mass = mass
27        # works more dynamically27        # 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 = False29        self.used = False
3030
31    @property31    @property
32    def volume(self):32    def volume(self):
33        return self.mass / self.density33        return self.mass / self.density
3434
3535
36class Brick(Material):36class Brick(Material):
37    """Represents a class for a brick."""37    """Represents a class for a brick."""
3838
39    skip39    skip
4040
4141
42class Concrete(Material):42class Concrete(Material):
43    """Represents a class for a concrete."""43    """Represents a class for a concrete."""
4444
45    skip()45    skip()
4646
4747
48class Wood(Material):48class Wood(Material):
49    """Represents a class for a wood."""49    """Represents a class for a wood."""
5050
51    skip.skip51    skip.skip
5252
5353
54class Stone(Material):54class Stone(Material):
55    """Represents a class for a stone."""55    """Represents a class for a stone."""
5656
57    skip57    skip
5858
5959
60class Steel(Material):60class Steel(Material):
61    """Represents a class for a steel."""61    """Represents a class for a steel."""
6262
63    skip63    skip
6464
6565
66class Factory:66class Factory:
67    """Represents a factory for creating materials and alloys."""67    """Represents a factory for creating materials and alloys."""
6868
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': Stone74        'Stone': Stone
75    }75    }
n76    _all_created_materials = set()n76    _instances = []
7777
78    def __init__(self):78    def __init__(self):
t79        self._created_materials = set()t79        self.created_materials = []
80        self._instances.append(self)
81 
82    def __del__(self):
83        if self in self.instances:
84            self.instances.remove(self)
8085
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}')
8691
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 set94            self._created_materials.add(material)  # add to a set
90            self._all_created_materials.add(material)  # add to a set with all95            self._all_created_materials.add(material)  # add to a set with all
91            return_tuple += (material,)96            return_tuple += (material,)
9297
93        return return_tuple98        return return_tuple
9499
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)
100105
101        if class_name in self._created_classes:106        if class_name in self._created_classes:
102            # mark all materials as used107            # 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 = 0111            density = 0
107            for material in args:112            for material in args:
108                material.used = True113                material.used = True
109                density += Material.material_density_values[type(material).__name__]114                density += Material.material_density_values[type(material).__name__]
110115
111            Material.material_density_values[str(class_name)] = density / len(args)  # set the class density116            Material.material_density_values[str(class_name)] = density / len(args)  # set the class density
112            new_material_class = type(str(class_name), (Material,), {})  # dynamic class117            new_material_class = type(str(class_name), (Material,), {})  # dynamic class
113            self._created_classes[class_name] = new_material_class  # add a new class118            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)
115120
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 set122        self._created_materials.add(return_material)  # add to a set
118        self._all_created_materials.add(return_material)  # add to a set with all123        self._all_created_materials.add(return_material)  # add to a set with all
119        return return_material124        return return_material
120125
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')
126131
127        if args:  # positional132        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')
130135
131            return self.__create_materials_from_positional(args)136            return self.__create_materials_from_positional(args)
132137
133        if kwargs:  # named138        if kwargs:  # named
134            return self.__create_materials_from_named(kwargs)139            return self.__create_materials_from_named(kwargs)
135140
136    def can_build(self, quantity):141    def can_build(self, quantity):
137        volume = 0142        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.volume145                volume += material.volume
141146
142        return volume >= quantity147        return volume >= quantity
143148
144    @staticmethod149    @staticmethod
145    def can_build_together(quantity):150    def can_build_together(quantity):
146        volume = 0151        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.volume154                volume += material.volume
150155
151        return volume >= quantity156        return volume >= quantity
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1class DoNothing:f1class DoNothing:
2    """Represents a cool change for pass keyword."""2    """Represents a cool change for pass keyword."""
33
4    def __getattr__(self, _):4    def __getattr__(self, _):
5        return self5        return self
66
7    def __call__(self, *args, **kwargs):7    def __call__(self, *args, **kwargs):
8        pass8        pass
99
1010
11skip = DoNothing()11skip = DoNothing()
1212
1313
14class Material:14class Material:
15    """Represents a parent class for materials."""15    """Represents a parent class for materials."""
1616
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': 60022        'Wood': 600
23    }23    }
2424
25    def __init__(self, mass):25    def __init__(self, mass):
26        self.mass = mass26        self.mass = mass
27        # works more dynamically27        # 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 = False29        self.used = False
3030
31    @property31    @property
32    def volume(self):32    def volume(self):
33        return self.mass / self.density33        return self.mass / self.density
3434
3535
36class Brick(Material):36class Brick(Material):
37    """Represents a class for a brick."""37    """Represents a class for a brick."""
3838
39    skip39    skip
4040
4141
42class Concrete(Material):42class Concrete(Material):
43    """Represents a class for a concrete."""43    """Represents a class for a concrete."""
4444
45    skip()45    skip()
4646
4747
48class Wood(Material):48class Wood(Material):
49    """Represents a class for a wood."""49    """Represents a class for a wood."""
5050
51    skip.skip51    skip.skip
5252
5353
54class Stone(Material):54class Stone(Material):
55    """Represents a class for a stone."""55    """Represents a class for a stone."""
5656
57    skip57    skip
5858
5959
60class Steel(Material):60class Steel(Material):
61    """Represents a class for a steel."""61    """Represents a class for a steel."""
6262
63    skip63    skip
6464
6565
66class Factory:66class Factory:
67    """Represents a factory for creating materials and alloys."""67    """Represents a factory for creating materials and alloys."""
6868
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': Stone74        'Stone': Stone
75    }75    }
76    _all_created_materials = set()76    _all_created_materials = set()
7777
78    def __init__(self):78    def __init__(self):
79        self._created_materials = set()79        self._created_materials = set()
8080
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():
n84            if key in self._created_classes:n84            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}')
nn86 
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,)
9292
93        return return_tuple93        return return_tuple
9494
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)
100100
n101        if class_name in self._created_classes.keys():n101        if class_name in self._created_classes:
102            # mark all materials as used102            # mark all materials as used
103            [setattr(material, 'used', True) for material in args]103            [setattr(material, 'used', True) for material in args]
n104            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)
n106            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 = 0106            density = 0
112            for material in args:107            for material in args:
113                material.used = True108                material.used = True
n114                density += Material.material_density_values[str(type(material).__name__)]n109                density += Material.material_density_values[type(material).__name__]
115110
116            Material.material_density_values[str(class_name)] = density / len(args)  # set the class density111            Material.material_density_values[str(class_name)] = density / len(args)  # set the class density
117            new_material_class = type(str(class_name), (Material,), {})  # dynamic class112            new_material_class = type(str(class_name), (Material,), {})  # dynamic class
n118 n
119            self._created_classes[class_name] = new_material_class  # add a new class113            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)
n121            return_material = new_material_class(mass)n115 
116        return_material = self._created_classes[class_name](mass)
122            self._created_materials.add(return_material)  # add to a set117        self._created_materials.add(return_material)  # add to a set
123            Factory._all_created_materials.add(return_material)  # add to a set with all118        self._all_created_materials.add(return_material)  # add to a set with all
124            return return_material119        return return_material
125120
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')
131126
132        if args:  # positional127        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')
135130
136            return self.__create_materials_from_positional(args)131            return self.__create_materials_from_positional(args)
137132
138        if kwargs:  # named133        if kwargs:  # named
139            return self.__create_materials_from_named(kwargs)134            return self.__create_materials_from_named(kwargs)
140135
141    def can_build(self, quantity):136    def can_build(self, quantity):
142        volume = 0137        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.volume140                volume += material.volume
146141
147        return volume >= quantity142        return volume >= quantity
148143
149    @staticmethod144    @staticmethod
150    def can_build_together(quantity):145    def can_build_together(quantity):
151        volume = 0146        volume = 0
152        for material in Factory._all_created_materials:147        for material in Factory._all_created_materials:
n153            if material.used is False:n148            if not material.used:
154                volume += material.volume149                volume += material.volume
155150
156        return volume >= quantity151        return volume >= quantity
t157 t
158factory1 = Factory()
159factory2 = Factory()
160wood1, steel1, brick1, stone1, concrete1 = factory1(Wood=5, Steel=15, Brick=60, Stone=300, Concrete=20)
161wood2, steel2, brick2, stone2, concrete2 = factory2(Wood=5, Steel=30, Brick=300, Stone=600, Concrete=2000)
162 
163result1 = factory1(wood1, brick1)
164result2 = factory2(concrete2, stone1)
165result = factory1(result1, result2)
166print(result.__class__.__name__)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

t1class DoNothing:t1class DoNothing:
2    """Represents a cool change for pass keyword."""2    """Represents a cool change for pass keyword."""
33
4    def __getattr__(self, _):4    def __getattr__(self, _):
5        return self5        return self
66
7    def __call__(self, *args, **kwargs):7    def __call__(self, *args, **kwargs):
8        pass8        pass
99
1010
11skip = DoNothing()11skip = DoNothing()
1212
1313
14class Material:14class Material:
15    """Represents a parent class for materials."""15    """Represents a parent class for materials."""
1616
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': 60022        'Wood': 600
23    }23    }
2424
25    def __init__(self, mass):25    def __init__(self, mass):
26        self.mass = mass26        self.mass = mass
27        # works more dynamically27        # 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 = False29        self.used = False
3030
31    @property31    @property
32    def volume(self):32    def volume(self):
33        return self.mass / self.density33        return self.mass / self.density
3434
3535
36class Brick(Material):36class Brick(Material):
37    """Represents a class for a brick."""37    """Represents a class for a brick."""
3838
39    skip39    skip
4040
4141
42class Concrete(Material):42class Concrete(Material):
43    """Represents a class for a concrete."""43    """Represents a class for a concrete."""
4444
45    skip()45    skip()
4646
4747
48class Wood(Material):48class Wood(Material):
49    """Represents a class for a wood."""49    """Represents a class for a wood."""
5050
51    skip.skip51    skip.skip
5252
5353
54class Stone(Material):54class Stone(Material):
55    """Represents a class for a stone."""55    """Represents a class for a stone."""
5656
57    skip57    skip
5858
5959
60class Steel(Material):60class Steel(Material):
61    """Represents a class for a steel."""61    """Represents a class for a steel."""
6262
63    skip63    skip
6464
6565
66class Factory:66class Factory:
67    """Represents a factory for creating materials and alloys."""67    """Represents a factory for creating materials and alloys."""
6868
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': Stone74        'Stone': Stone
75    }75    }
76    _all_created_materials = set()76    _all_created_materials = set()
7777
78    def __init__(self):78    def __init__(self):
79        self._created_materials = set()79        self._created_materials = set()
8080
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 set87                self._created_materials.add(material)  # add to a set
88                Factory._all_created_materials.add(material)  # add to a set with all88                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}')
9292
93        return return_tuple93        return return_tuple
9494
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)
100100
101        if class_name in self._created_classes.keys():101        if class_name in self._created_classes.keys():
102            # mark all materials as used102            # 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 set107            self._created_materials.add(return_material)  # add to a set
108            self._all_created_materials.add(return_material)  # add to a set with all108            self._all_created_materials.add(return_material)  # add to a set with all
109            return return_material109            return return_material
110        else:110        else:
111            density = 0111            density = 0
112            for material in args:112            for material in args:
113                material.used = True113                material.used = True
114                density += Material.material_density_values[str(type(material).__name__)]114                density += Material.material_density_values[str(type(material).__name__)]
115115
116            Material.material_density_values[str(class_name)] = density / len(args)  # set the class density116            Material.material_density_values[str(class_name)] = density / len(args)  # set the class density
117            new_material_class = type(str(class_name), (Material,), {})  # dynamic class117            new_material_class = type(str(class_name), (Material,), {})  # dynamic class
118118
119            self._created_classes[class_name] = new_material_class  # add a new class119            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 set122            self._created_materials.add(return_material)  # add to a set
123            Factory._all_created_materials.add(return_material)  # add to a set with all123            Factory._all_created_materials.add(return_material)  # add to a set with all
124            return return_material124            return return_material
125125
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')
131131
132        if args:  # positional132        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')
135135
136            return self.__create_materials_from_positional(args)136            return self.__create_materials_from_positional(args)
137137
138        if kwargs:  # named138        if kwargs:  # named
139            return self.__create_materials_from_named(kwargs)139            return self.__create_materials_from_named(kwargs)
140140
141    def can_build(self, quantity):141    def can_build(self, quantity):
142        volume = 0142        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.volume145                volume += material.volume
146146
147        return volume >= quantity147        return volume >= quantity
148148
149    @staticmethod149    @staticmethod
150    def can_build_together(quantity):150    def can_build_together(quantity):
151        volume = 0151        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.volume154                volume += material.volume
155155
156        return volume >= quantity156        return volume >= quantity
157157
158factory1 = Factory()158factory1 = Factory()
159factory2 = Factory()159factory2 = Factory()
160wood1, steel1, brick1, stone1, concrete1 = factory1(Wood=5, Steel=15, Brick=60, Stone=300, Concrete=20)160wood1, steel1, brick1, stone1, concrete1 = factory1(Wood=5, Steel=15, Brick=60, Stone=300, Concrete=20)
161wood2, steel2, brick2, stone2, concrete2 = factory2(Wood=5, Steel=30, Brick=300, Stone=600, Concrete=2000)161wood2, steel2, brick2, stone2, concrete2 = factory2(Wood=5, Steel=30, Brick=300, Stone=600, Concrete=2000)
162162
163result1 = factory1(wood1, brick1)163result1 = factory1(wood1, brick1)
164result2 = factory2(concrete2, stone1)164result2 = factory2(concrete2, stone1)
165result = factory1(result1, result2)165result = factory1(result1, result2)
166print(result.__class__.__name__)166print(result.__class__.__name__)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1class DoNothing:f1class DoNothing:
nn2    """Represents a cool change for pass keyword."""
3 
2    def __getattr__(self, _):4    def __getattr__(self, _):
3        return self5        return self
nn6 
4    def __call__(self, *args, **kwargs):7    def __call__(self, *args, **kwargs):
5        pass8        pass
69
nn10 
7skip = DoNothing()11skip = DoNothing()
nn12 
813
9class Material:14class Material:
10    """Represents a parent class for materials."""15    """Represents a parent class for materials."""
1116
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': 60022        'Wood': 600
18    }23    }
1924
20    def __init__(self, mass):25    def __init__(self, mass):
21        self.mass = mass26        self.mass = mass
nn27        # works more dynamically
22        self.density = Material.material_density_values[self.__class__.__name__] # works more dynamically28        self.density = Material.material_density_values[self.__class__.__name__]
23        self.used = False29        self.used = False
2430
25    @property31    @property
26    def volume(self):32    def volume(self):
27        return self.mass / self.density33        return self.mass / self.density
2834
nn35 
29class Brick(Material):36class Brick(Material):
30    """Represents a class for a brick."""37    """Represents a class for a brick."""
nn38 
31    skip39    skip
nn40 
3241
33class Concrete(Material):42class Concrete(Material):
34    """Represents a class for a concrete."""43    """Represents a class for a concrete."""
nn44 
35    skip()45    skip()
nn46 
3647
37class Wood(Material):48class Wood(Material):
38    """Represents a class for a wood."""49    """Represents a class for a wood."""
nn50 
39    skip.skip51    skip.skip
nn52 
4053
41class Stone(Material):54class Stone(Material):
42    """Represents a class for a stone."""55    """Represents a class for a stone."""
nn56 
43    skip57    skip
nn58 
4459
45class Steel(Material):60class Steel(Material):
46    """Represents a class for a steel."""61    """Represents a class for a steel."""
nn62 
47    skip63    skip
nn64 
4865
49class Factory:66class Factory:
50    """Represents a factory for creating materials and alloys."""67    """Represents a factory for creating materials and alloys."""
5168
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': Stone74        'Stone': Stone
58    }75    }
59    _all_created_materials = set()76    _all_created_materials = set()
6077
61    def __init__(self):78    def __init__(self):
62        self._created_materials = set()79        self._created_materials = set()
6380
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)
n70                self._created_materials.add(material) # add to a setn87                self._created_materials.add(material)  # add to a set
71                Factory._all_created_materials.add(material) # add to a set with all88                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}')
7592
76        return return_tuple93        return return_tuple
7794
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)
83100
84        if class_name in self._created_classes.keys():101        if class_name in self._created_classes.keys():
nn102            # mark all materials as used
85            [setattr(material, 'used', True) for material in args]  # mark all materials as used103            [setattr(material, 'used', True) for material in args]
86            material_class = self._created_classes[class_name]104            material_class = self._created_classes[class_name]
n87            return_material = material_class(sum(material.mass for material in args))n105            mass = sum(material.mass for material in args)
106            return_material = material_class(mass)
88            self._created_materials.add(return_material)  # add to a set107            self._created_materials.add(return_material)  # add to a set
89            self._all_created_materials.add(return_material)  # add to a set with all108            self._all_created_materials.add(return_material)  # add to a set with all
90            return return_material109            return return_material
91        else:110        else:
92            density = 0111            density = 0
93            for material in args:112            for material in args:
94                material.used = True113                material.used = True
95                density += Material.material_density_values[str(type(material).__name__)]114                density += Material.material_density_values[str(type(material).__name__)]
96115
97            Material.material_density_values[str(class_name)] = density / len(args)  # set the class density116            Material.material_density_values[str(class_name)] = density / len(args)  # set the class density
98            new_material_class = type(str(class_name), (Material,), {})  # dynamic class117            new_material_class = type(str(class_name), (Material,), {})  # dynamic class
99118
100            self._created_classes[class_name] = new_material_class  # add a new class119            self._created_classes[class_name] = new_material_class  # add a new class
nn120            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 set122            self._created_materials.add(return_material)  # add to a set
103            Factory._all_created_materials.add(return_material)  # add to a set with all123            Factory._all_created_materials.add(return_material)  # add to a set with all
104            return return_material124            return return_material
105125
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')
111131
n112        if args: # positionaln132        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')
115135
116            return self.__create_materials_from_positional(args)136            return self.__create_materials_from_positional(args)
117137
t118        if kwargs: # namedt138        if kwargs:  # named
119            return self.__create_materials_from_named(kwargs)139            return self.__create_materials_from_named(kwargs)
120140
121    def can_build(self, quantity):141    def can_build(self, quantity):
122        volume = 0142        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.volume145                volume += material.volume
126146
127        return volume >= quantity147        return volume >= quantity
128148
129    @staticmethod149    @staticmethod
130    def can_build_together(quantity):150    def can_build_together(quantity):
131        volume = 0151        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.volume154                volume += material.volume
135155
136        return volume >= quantity156        return volume >= quantity
137157
138factory1 = Factory()158factory1 = Factory()
139factory2 = Factory()159factory2 = Factory()
140wood1, steel1, brick1, stone1, concrete1 = factory1(Wood=5, Steel=15, Brick=60, Stone=300, Concrete=20)160wood1, steel1, brick1, stone1, concrete1 = factory1(Wood=5, Steel=15, Brick=60, Stone=300, Concrete=20)
141wood2, steel2, brick2, stone2, concrete2 = factory2(Wood=5, Steel=30, Brick=300, Stone=600, Concrete=2000)161wood2, steel2, brick2, stone2, concrete2 = factory2(Wood=5, Steel=30, Brick=300, Stone=600, Concrete=2000)
142162
143result1 = factory1(wood1, brick1)163result1 = factory1(wood1, brick1)
144result2 = factory2(concrete2, stone1)164result2 = factory2(concrete2, stone1)
145result = factory1(result1, result2)165result = factory1(result1, result2)
146print(result.__class__.__name__)166print(result.__class__.__name__)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op