Домашни > Another brick in the wall > Решения > Решението на Йована Божилов

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

5 точки общо

5 успешни теста
5 неуспешни теста
Код (Домашна работа 4)

  1class Material:
  2    def __init__(self, mass: int, density: int):
  3        self.mass = mass
  4        self._density = density
  5        self._valid = True  
  6
  7    @property
  8    def volume(self):
  9        return self.mass / self._density
 10
 11    def invalidate(self):
 12        self._valid = False
 13
 14    def is_valid(self):
 15        return self._valid
 16
 17def create_material_class(name, density):
 18    return type(
 19        name,
 20        (Material,),
 21        {
 22            "__init__": lambda self, mass: super(type(self), self).__init__(mass, density)
 23        }
 24    )
 25
 26class Factory:
 27    _dynamic_classes = {}  
 28    _created_objects = []
 29    _material_classes = {}  
 30
 31    def __init__(self):
 32        self._materials = []
 33
 34    @classmethod
 35    def register_material_class(cls, name, material_class):
 36        cls._material_classes[name] = material_class
 37
 38    def __call__(self, *args, **kwargs):
 39        if args and kwargs:
 40            raise ValueError("Cannot mix positional and keyword arguments.")
 41        if not args and not kwargs:
 42            raise ValueError("Cannot call factory without arguments.")
 43
 44        if args:  
 45            return self._handle_positional(args)
 46        elif kwargs: 
 47            return self._handle_keyword(kwargs)
 48
 49    def _handle_positional(self, args):
 50        if any(not material.is_valid() for material in args):
 51            raise AssertionError("Material has already been used.")
 52
 53        class_names = sorted(type(arg).__name__ for arg in args)
 54        combined_material_name = "_".join(class_names)
 55        
 56        if combined_material_name not in Factory._dynamic_classes:
 57            avg_density = sum(arg._density for arg in args) / len(args)
 58
 59            class DynamicMaterial(Material):
 60                def __init__(self, mass: int):
 61                    super().__init__(mass, avg_density)
 62
 63            DynamicMaterial.__name__ = combined_material_name
 64            Factory._dynamic_classes[combined_material_name] = DynamicMaterial
 65
 66        for material in args:
 67            material.invalidate()
 68
 69        new_class = Factory._dynamic_classes[combined_material_name]
 70        mass = sum(material.mass for material in args)
 71        instance = new_class(mass)
 72        self._materials.append(instance)
 73        
 74        return instance
 75
 76    def _handle_keyword(self, kwargs):
 77        instances = []
 78        for key, mass in kwargs.items():
 79            if key not in self._material_classes:
 80                raise ValueError(f"Unknown material type: {key}")
 81            material_class = self._material_classes[key]
 82            instance = material_class(mass)
 83            instances.append(instance)
 84            self._materials.append(instance)
 85        return tuple(instances)
 86
 87    def can_build(self, volume: int):
 88        total_volume = sum(mat.volume for mat in self._materials if mat.is_valid())
 89        return total_volume >= volume
 90
 91    @classmethod
 92    def can_build_together(cls, volume: int):
 93        total_volume = sum(mat.volume for mat in cls._created_objects if mat.is_valid())
 94        return total_volume >= volume
 95
 96Concrete = create_material_class("Concrete", 2500)
 97Brick = create_material_class("Brick", 2000)
 98Stone = create_material_class("Stone", 1600)
 99Wood = create_material_class("Wood", 600)
100Steel = create_material_class("Steel", 7700)
101
102Factory.register_material_class("Concrete", Concrete)
103Factory.register_material_class("Brick", Brick)
104Factory.register_material_class("Stone", Stone)
105Factory.register_material_class("Wood", Wood)
106Factory.register_material_class("Steel", Steel)

.FE.E.FF..
======================================================================
ERROR: test_materials_between_factories (test.TestFactory.test_materials_between_factories)
Test materials sharing.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 156, in test_materials_between_factories
result2, = self.factory2(Brick_Concrete_Steel_Stone_Wood=2)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 47, in __call__
return self._handle_keyword(kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 80, in _handle_keyword
raise ValueError(f"Unknown material type: {key}")
ValueError: Unknown material type: Brick_Concrete_Steel_Stone_Wood

======================================================================
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 145, in test_named_arguments_with_dynamically_created_classes
result2, = self.factory1(Brick_Concrete_Steel_Stone_Wood=2)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 47, in __call__
return self._handle_keyword(kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 80, in _handle_keyword
raise ValueError(f"Unknown material type: {key}")
ValueError: Unknown material type: Brick_Concrete_Steel_Stone_Wood

======================================================================
FAIL: test_can_build (test.TestFactory.test_can_build)
Test can_build methods.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 178, in test_can_build
self.assertTrue(self.factory2.can_build_together(6.0))
AssertionError: False is not true

======================================================================
FAIL: 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 128, in test_positional_arguments_multiple_argument_with_dynamics
self.assertEqual(mega_material.__class__.__name__,
AssertionError: 'Brick_Concrete_Stone_Steel_Wood' != 'Brick_Concrete_Steel_Stone_Wood'
- Brick_Concrete_Stone_Steel_Wood
? ------
+ Brick_Concrete_Steel_Stone_Wood
? ++++++

======================================================================
FAIL: test_positional_arguments_single_argument (test.TestFactory.test_positional_arguments_single_argument)
Test calling a factory using a sigle positional argument.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 80, in test_positional_arguments_single_argument
self.assertIs(type(concrete2), solution.Concrete)
AssertionError: <class 'solution.Factory._handle_positional.<locals>.DynamicMaterial'> is not <class 'solution.Concrete'>

----------------------------------------------------------------------
Ran 10 tests in 0.011s

FAILED (failures=3, errors=2)

Дискусия
История

f1class Material:f1class Material:
2    def __init__(self, mass: int, density: int):2    def __init__(self, mass: int, density: int):
3        self.mass = mass3        self.mass = mass
4        self._density = density4        self._density = density
5        self._valid = True  5        self._valid = True  
66
7    @property7    @property
8    def volume(self):8    def volume(self):
9        return self.mass / self._density9        return self.mass / self._density
1010
11    def invalidate(self):11    def invalidate(self):
12        self._valid = False12        self._valid = False
1313
14    def is_valid(self):14    def is_valid(self):
15        return self._valid15        return self._valid
1616
n17 n17def create_material_class(name, density):
18class Concrete(Material):18    return type(
19    def __init__(self, mass: int):19        name,
20        super().__init__(mass, 2500)20        (Material,),
21 21        {
22 22            "__init__": lambda self, mass: super(type(self), self).__init__(mass, density)
23class Brick(Material):23        }
24    def __init__(self, mass: int):24    )
25        super().__init__(mass, 2000)
26 
27 
28class Stone(Material):
29    def __init__(self, mass: int):
30        super().__init__(mass, 1600)
31 
32 
33class Wood(Material):
34    def __init__(self, mass: int):
35        super().__init__(mass, 600)
36 
37 
38class Steel(Material):
39    def __init__(self, mass: int):
40        super().__init__(mass, 7700)
41 
4225
43class Factory:26class Factory:
44    _dynamic_classes = {}  27    _dynamic_classes = {}  
45    _created_objects = []28    _created_objects = []
nn29    _material_classes = {}  
4630
47    def __init__(self):31    def __init__(self):
48        self._materials = []32        self._materials = []
nn33 
34    @classmethod
35    def register_material_class(cls, name, material_class):
36        cls._material_classes[name] = material_class
4937
50    def __call__(self, *args, **kwargs):38    def __call__(self, *args, **kwargs):
51        if args and kwargs:39        if args and kwargs:
52            raise ValueError("Cannot mix positional and keyword arguments.")40            raise ValueError("Cannot mix positional and keyword arguments.")
53        if not args and not kwargs:41        if not args and not kwargs:
54            raise ValueError("Cannot call factory without arguments.")42            raise ValueError("Cannot call factory without arguments.")
5543
n56        if args: n44        if args:  
57            return self._handle_positional(args)45            return self._handle_positional(args)
n58        elif kwargs:  n46        elif kwargs: 
59            return self._handle_keyword(kwargs)47            return self._handle_keyword(kwargs)
6048
61    def _handle_positional(self, args):49    def _handle_positional(self, args):
n62        for material in args:n50        if any(not material.is_valid() for material in args):
63            if not material.is_valid():
64                raise AssertionError("Material has already been used.")51            raise AssertionError("Material has already been used.")
52 
65        class_names = sorted(type(arg).__name__ for arg in args)53        class_names = sorted(type(arg).__name__ for arg in args)
n66        class_key = "_".join(class_names)n54        combined_material_name = "_".join(class_names)
55        
67        if class_key not in Factory._dynamic_classes:56        if combined_material_name not in Factory._dynamic_classes:
68            avg_density = sum(arg._density for arg in args) / len(args)57            avg_density = sum(arg._density for arg in args) / len(args)
6958
70            class DynamicMaterial(Material):59            class DynamicMaterial(Material):
71                def __init__(self, mass: int):60                def __init__(self, mass: int):
72                    super().__init__(mass, avg_density)61                    super().__init__(mass, avg_density)
7362
n74            DynamicMaterial.__name__ = class_keyn63            DynamicMaterial.__name__ = combined_material_name
75            Factory._dynamic_classes[class_key] = DynamicMaterial64            Factory._dynamic_classes[combined_material_name] = DynamicMaterial
7665
77        for material in args:66        for material in args:
78            material.invalidate()67            material.invalidate()
nn68 
79        new_class = Factory._dynamic_classes[class_key]69        new_class = Factory._dynamic_classes[combined_material_name]
80        mass = sum(material.mass for material in args)70        mass = sum(material.mass for material in args)
81        instance = new_class(mass)71        instance = new_class(mass)
82        self._materials.append(instance)72        self._materials.append(instance)
nn73        
83        return instance74        return instance
8475
85    def _handle_keyword(self, kwargs):76    def _handle_keyword(self, kwargs):
86        instances = []77        instances = []
87        for key, mass in kwargs.items():78        for key, mass in kwargs.items():
n88            if key not in globals():n79            if key not in self._material_classes:
89                raise ValueError(f"Unknown material type: {key}")80                raise ValueError(f"Unknown material type: {key}")
n90            material_class = globals()[key]n81            material_class = self._material_classes[key]
91            instance = material_class(mass)82            instance = material_class(mass)
92            instances.append(instance)83            instances.append(instance)
93            self._materials.append(instance)84            self._materials.append(instance)
94        return tuple(instances)85        return tuple(instances)
9586
96    def can_build(self, volume: int):87    def can_build(self, volume: int):
97        total_volume = sum(mat.volume for mat in self._materials if mat.is_valid())88        total_volume = sum(mat.volume for mat in self._materials if mat.is_valid())
98        return total_volume >= volume89        return total_volume >= volume
9990
100    @classmethod91    @classmethod
101    def can_build_together(cls, volume: int):92    def can_build_together(cls, volume: int):
102        total_volume = sum(mat.volume for mat in cls._created_objects if mat.is_valid())93        total_volume = sum(mat.volume for mat in cls._created_objects if mat.is_valid())
103        return total_volume >= volume94        return total_volume >= volume
tt95 
96Concrete = create_material_class("Concrete", 2500)
97Brick = create_material_class("Brick", 2000)
98Stone = create_material_class("Stone", 1600)
99Wood = create_material_class("Wood", 600)
100Steel = create_material_class("Steel", 7700)
101 
102Factory.register_material_class("Concrete", Concrete)
103Factory.register_material_class("Brick", Brick)
104Factory.register_material_class("Stone", Stone)
105Factory.register_material_class("Wood", Wood)
106Factory.register_material_class("Steel", Steel)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op