Домашни > Another brick in the wall > Решения > Решението на Енисел Кунч

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

6 точки общо

6 успешни теста
4 неуспешни теста
Код

  1class Material:
  2    THICKNESS = 0
  3    def __init__(self, mass: int):
  4        self.mass = mass
  5
  6    @property
  7    def volume(self):
  8        return float(self.mass / self.THICKNESS)
  9
 10
 11class Concrete(Material):
 12    THICKNESS = 2500
 13
 14
 15class Brick(Material):
 16    THICKNESS = 2000
 17
 18
 19class Stone(Material):
 20    THICKNESS = 1600
 21
 22
 23class Wood(Material):
 24    THICKNESS = 600
 25
 26
 27class Steel(Material):
 28    THICKNESS = 7700
 29
 30
 31class Factory:
 32    _dynamic_classes = {}
 33    all_created_materials = set()  
 34    used_materials = set()  
 35
 36    def __init__(self):
 37        self.current_materials = set()  
 38
 39    def __call__(self, *args, **kwargs):
 40        if args and kwargs:
 41            raise ValueError("Cannot mix positional and keyword arguments.")
 42        if not args and not kwargs:
 43            raise ValueError("Cannot call the function without arguments.")
 44
 45        if args:
 46            return self._call_with_positional_args(args)
 47        if kwargs:
 48            return self._call_with_keyword_args(kwargs)
 49
 50    def _call_with_keyword_args(self, kwargs):
 51        ALLOWED_NAMES = {
 52            "Concrete": Concrete,
 53            "Brick": Brick,
 54            "Stone": Stone,
 55            "Wood": Wood,
 56            "Steel": Steel,
 57        }
 58
 59        result = []
 60        for name, mass in kwargs.items():
 61            if name not in ALLOWED_NAMES and name not in Factory._dynamic_classes:
 62                raise ValueError(f"Invalid material type: {name}")
 63            material_class = (
 64                ALLOWED_NAMES.get(name) or Factory._dynamic_classes[name]
 65            )
 66            material = material_class(mass)
 67            self.current_materials.add(material)
 68            Factory.all_created_materials.add(material)
 69            result.append(material)
 70
 71        return tuple(result)
 72
 73    def _call_with_positional_args(self, args):
 74        for material in args:
 75            if material in Factory.used_materials:
 76                raise AssertionError("This material has already been used.")
 77            if not isinstance(material, Material):
 78                raise ValueError("Positional arguments must be instances of Materials.")
 79            Factory.used_materials.add(material)
 80
 81        base_classes_names = []
 82        for arg in args:
 83            base_classes_names += type(arg).__name__.split('_')
 84
 85        sorted_materials_names = sorted(base_classes_names)
 86        new_class_name = '_'.join(sorted_materials_names)
 87
 88        if new_class_name not in Factory._dynamic_classes:
 89            avg_thickness = sum(material.THICKNESS for material in args) / len(args)
 90            new_class = type(new_class_name, (Material,), {"THICKNESS": avg_thickness})
 91            Factory._dynamic_classes[new_class_name] = new_class
 92
 93        new_class = Factory._dynamic_classes[new_class_name]
 94        total_mass = sum(material.mass for material in args)
 95        new_material = new_class(total_mass)
 96
 97        self.current_materials.add(new_material)
 98        Factory.all_created_materials.add(new_material)
 99        return new_material
100
101    def can_build(self, necessary_volume: int):
102        total_volume = sum(
103            instance.volume
104            for instance in self.current_materials
105            if instance not in Factory.used_materials
106        )
107        return total_volume >= necessary_volume
108
109    @classmethod
110    def can_build_together(cls, necessary_volume: int):
111        total_volume = sum(
112            instance.volume
113            for instance in cls.all_created_materials
114            if instance not in cls.used_materials or isinstance(instance, Material)
115        )
116        return total_volume >= necessary_volume

.F...FFF..
======================================================================
FAIL: test_can_build (test.TestFactory.test_can_build)
Test can_build methods.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 177, in test_can_build
self.assertFalse(solution.Factory.can_build_together(6.0001))
AssertionError: True is not false

======================================================================
FAIL: test_positional_arguments_multiple_argument_from_initial_set (test.TestFactory.test_positional_arguments_multiple_argument_from_initial_set)
Test calling a factory using multiple positional arguments.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 116, in test_positional_arguments_multiple_argument_from_initial_set
concrete_wood = self.factory1(concrete, wood)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 46, in __call__
return self._call_with_positional_args(args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 76, in _call_with_positional_args
raise AssertionError("This material has already been used.")
AssertionError: This material has already been used.

======================================================================
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 130, in test_positional_arguments_multiple_argument_with_dynamics
self.assertAlmostEqual(mega_material.volume, 6.77, places=2) # mass=19500, density=2880
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 5.661290322580645 != 6.77 within 2 places (1.1087096774193546 difference)

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

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

FAILED (failures=4)

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

n1class Materials:n1class Material:
2    THICKNESS = 0
2    def __init__(self, mass: int):3    def __init__(self, mass: int):
3        self.mass = mass4        self.mass = mass
45
5    @property6    @property
6    def volume(self):7    def volume(self):
n7        return float(self.mass / self.thickness)n8        return float(self.mass / self.THICKNESS)
89
910
n10class Concrete(Materials):n11class Concrete(Material):
11    thickness = 250012    THICKNESS = 2500
1213
1314
n14class Brick(Materials):n15class Brick(Material):
15    thickness = 200016    THICKNESS = 2000
1617
1718
n18class Stone(Materials):n19class Stone(Material):
19    thickness = 160020    THICKNESS = 1600
2021
2122
n22class Wood(Materials):n23class Wood(Material):
23    thickness = 60024    THICKNESS = 600
2425
2526
n26class Steel(Materials):n27class Steel(Material):
27    thickness = 770028    THICKNESS = 7700
2829
2930
30class Factory:31class Factory:
31    _dynamic_classes = {}32    _dynamic_classes = {}
32    all_created_materials = set()  33    all_created_materials = set()  
33    used_materials = set()  34    used_materials = set()  
3435
35    def __init__(self):36    def __init__(self):
36        self.current_materials = set()  37        self.current_materials = set()  
3738
38    def __call__(self, *args, **kwargs):39    def __call__(self, *args, **kwargs):
39        if args and kwargs:40        if args and kwargs:
40            raise ValueError("Cannot mix positional and keyword arguments.")41            raise ValueError("Cannot mix positional and keyword arguments.")
41        if not args and not kwargs:42        if not args and not kwargs:
42            raise ValueError("Cannot call the function without arguments.")43            raise ValueError("Cannot call the function without arguments.")
4344
44        if args:45        if args:
45            return self._call_with_positional_args(args)46            return self._call_with_positional_args(args)
46        if kwargs:47        if kwargs:
47            return self._call_with_keyword_args(kwargs)48            return self._call_with_keyword_args(kwargs)
4849
49    def _call_with_keyword_args(self, kwargs):50    def _call_with_keyword_args(self, kwargs):
n50        allowed_names = {n51        ALLOWED_NAMES = {
51            "Concrete": Concrete,52            "Concrete": Concrete,
52            "Brick": Brick,53            "Brick": Brick,
53            "Stone": Stone,54            "Stone": Stone,
54            "Wood": Wood,55            "Wood": Wood,
55            "Steel": Steel,56            "Steel": Steel,
56        }57        }
5758
58        result = []59        result = []
59        for name, mass in kwargs.items():60        for name, mass in kwargs.items():
n60            if name not in allowed_names and name not in Factory._dynamic_classes:n61            if name not in ALLOWED_NAMES and name not in Factory._dynamic_classes:
61                raise ValueError(f"Invalid material type: {name}")62                raise ValueError(f"Invalid material type: {name}")
62            material_class = (63            material_class = (
n63                allowed_names.get(name) or Factory._dynamic_classes[name]n64                ALLOWED_NAMES.get(name) or Factory._dynamic_classes[name]
64            )65            )
65            material = material_class(mass)66            material = material_class(mass)
66            self.current_materials.add(material)67            self.current_materials.add(material)
67            Factory.all_created_materials.add(material)68            Factory.all_created_materials.add(material)
68            result.append(material)69            result.append(material)
6970
70        return tuple(result)71        return tuple(result)
7172
72    def _call_with_positional_args(self, args):73    def _call_with_positional_args(self, args):
73        for material in args:74        for material in args:
74            if material in Factory.used_materials:75            if material in Factory.used_materials:
75                raise AssertionError("This material has already been used.")76                raise AssertionError("This material has already been used.")
n76            if not isinstance(material, Materials):n77            if not isinstance(material, Material):
77                raise ValueError("Positional arguments must be instances of Materials.")78                raise ValueError("Positional arguments must be instances of Materials.")
78            Factory.used_materials.add(material)79            Factory.used_materials.add(material)
7980
80        base_classes_names = []81        base_classes_names = []
81        for arg in args:82        for arg in args:
82            base_classes_names += type(arg).__name__.split('_')83            base_classes_names += type(arg).__name__.split('_')
8384
84        sorted_materials_names = sorted(base_classes_names)85        sorted_materials_names = sorted(base_classes_names)
85        new_class_name = '_'.join(sorted_materials_names)86        new_class_name = '_'.join(sorted_materials_names)
8687
87        if new_class_name not in Factory._dynamic_classes:88        if new_class_name not in Factory._dynamic_classes:
n88            avg_thickness = sum(material.thickness for material in args) / len(args)n89            avg_thickness = sum(material.THICKNESS for material in args) / len(args)
89            new_class = type(new_class_name, (Materials,), {"thickness": avg_thickness})90            new_class = type(new_class_name, (Material,), {"THICKNESS": avg_thickness})
90            Factory._dynamic_classes[new_class_name] = new_class91            Factory._dynamic_classes[new_class_name] = new_class
9192
92        new_class = Factory._dynamic_classes[new_class_name]93        new_class = Factory._dynamic_classes[new_class_name]
93        total_mass = sum(material.mass for material in args)94        total_mass = sum(material.mass for material in args)
94        new_material = new_class(total_mass)95        new_material = new_class(total_mass)
9596
96        self.current_materials.add(new_material)97        self.current_materials.add(new_material)
97        Factory.all_created_materials.add(new_material)98        Factory.all_created_materials.add(new_material)
98        return new_material99        return new_material
99100
100    def can_build(self, necessary_volume: int):101    def can_build(self, necessary_volume: int):
101        total_volume = sum(102        total_volume = sum(
102            instance.volume103            instance.volume
103            for instance in self.current_materials104            for instance in self.current_materials
104            if instance not in Factory.used_materials105            if instance not in Factory.used_materials
105        )106        )
106        return total_volume >= necessary_volume107        return total_volume >= necessary_volume
107108
108    @classmethod109    @classmethod
109    def can_build_together(cls, necessary_volume: int):110    def can_build_together(cls, necessary_volume: int):
110        total_volume = sum(111        total_volume = sum(
111            instance.volume112            instance.volume
112            for instance in cls.all_created_materials113            for instance in cls.all_created_materials
t113            if instance not in cls.used_materials or isinstance(instance, Materials)t114            if instance not in cls.used_materials or isinstance(instance, Material)
114        )115        )
115        return total_volume >= necessary_volume116        return total_volume >= necessary_volume
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op