Домашни > Another brick in the wall > Решения > Решението на Камелия Михайлова

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

7 точки общо

7 успешни теста
3 неуспешни теста
Код
Скрий всички коментари

  1class Material:
  2    def __init__(self, mass):
  3        self.mass = mass
  4        self._used = False 
  5
  6    @property
  7    def volume(self):
  8        return self.mass / self.density
  9
 10    def is_used(self):
 11        if self._used:
 12            raise AssertionError("Material has already been used.")
 13        self._used = True
 14
 15
 16class Concrete(Material):
 17    density = 2500
 18
 19
 20class Brick(Material):
 21    density = 2000
 22
 23
 24class Stone(Material):
 25    density = 1600
 26
 27
 28class Wood(Material):
 29    density = 600
 30
 31
 32class Steel(Material):
 33    density = 7700
 34
 35
 36class Factory:
 37    _dynamic_classes = {}
 38
 39    def __init__(self):
 40        self._materials = []
 41        self._used_materials = set()
 42
 43    def __call__(self, *args, **kwargs):
 44        if args and kwargs:
 45            raise ValueError("Can't mix positional and keyword arguments.")
 46        if not args and not kwargs:
 47            raise ValueError("Must provide either positional or keyword arguments.")
 48
 49        if kwargs:
 50            return self._handle_named_arguments(kwargs)
 51        return self._handle_positional_arguments(args)
 52
 53    def _handle_named_arguments(self, kwargs):
 54        instances = []
 55        for name, mass in kwargs.items():
 56            cls = self._get_material_class(name)
 57            if not cls:
 58                raise ValueError(f"Invalid material name: {name}")
 59            instance = cls(mass)
 60            instances.append(instance)
 61            self._materials.append(instance)
 62        return tuple(instances)
 63
 64    def _handle_positional_arguments(self, args):
 65        for material in args:
 66            material.is_used() 
 67
 68        material_classes = sorted(set(type(arg) for arg in args), key=lambda cls: cls.__name__)
 69        class_name = "_".join(cls.__name__ for cls in material_classes)
 70        if class_name not in Factory._dynamic_classes:
 71            density = sum(cls.density for cls in material_classes) / len(material_classes)
 72            Factory._dynamic_classes[class_name] = type(
 73                class_name, (Material,), {"density": density}
 74            )
 75        dynamic_class = Factory._dynamic_classes[class_name]
 76        total_mass = sum(arg.mass for arg in args)
 77        instance = dynamic_class(total_mass)
 78        self._materials.append(instance)
 79        return instance
 80
 81    def _get_material_class(self, name):
 82        return globals().get(name, Factory._dynamic_classes.get(name))
 83
 84    def can_build(self, volume):
 85        total_volume = sum(m.volume for m in self._materials if not m._used)
 86        return total_volume >= volume
 87
 88    @classmethod
 89    def can_build_together(cls, volume):
 90        total_volume = sum(
 91            m.volume
 92            for factory in Factory._all_instances()
 93            for m in factory._materials
 94            if not m._used
 95        )
 96        return total_volume >= volume
 97
 98    @staticmethod
 99    def _all_instances():
100        if not hasattr(Factory, "_instances"):
101            Factory._instances = []
102        return Factory._instances
103
104    def __new__(cls, *args, **kwargs):
105        instance = super().__new__(cls)
106        Factory._all_instances().append(instance)
107        return instance
108
109    

.....FFF..
======================================================================
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 51, in __call__
return self._handle_positional_arguments(args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 66, in _handle_positional_arguments
material.is_used()
File "/tmp/solution.py", line 12, in is_used
raise AssertionError("Material has already been used.")
AssertionError: 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 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.Concrete'> is not <class 'solution.Concrete'>

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

FAILED (failures=3)

Дискусия
Виктор Бечев
26.11.2024 17:23

Отвъд двете дребни забележки по-горе - решението изглежда добре.
История
Това решение има само една версия.