Домашни > Another brick in the wall > Решения > Решението на Елица Павлова

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

8 точки общо

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

  1MATERIAL_DENSITIES = {
  2    'Concrete': 2500,
  3    'Brick': 2000,
  4    'Stone': 1600,
  5    'Wood': 600,
  6    'Steel': 7700,
  7}
  8
  9class Material:
 10    def __init__(self, mass):
 11        self.mass = mass
 12        self._used = False
 13
 14    @property
 15    def density(self):
 16        return MATERIAL_DENSITIES[self.__class__.__name__]
 17
 18    @property
 19    def volume(self):
 20        return self.mass / self.density
 21
 22    def get_is_used(self):
 23        return self._used
 24
 25
 26class Concrete(Material):
 27    pass
 28
 29
 30class Brick(Material):
 31    pass
 32
 33
 34class Stone(Material):
 35    pass
 36
 37
 38class Wood(Material):
 39    pass
 40
 41
 42class Steel(Material):
 43    pass
 44
 45
 46class Factory:
 47    _dynamic_classes = {}
 48    _existing_factories = []
 49
 50    def __init__(self):
 51        self.materials = []
 52        Factory._existing_factories.append(self)
 53
 54    def __call__(self, *args, **kwargs):
 55        if args and kwargs:
 56            raise ValueError('Invalid operation: mix of positional and keyword arguments!')
 57        if not args and not kwargs:
 58            raise ValueError('Cannot create a factory without arguments!')
 59
 60        if args:
 61            return self._create_composite_material(args)
 62        if kwargs:
 63            return self._create_materials_from_kwargs(kwargs)
 64
 65    def _create_composite_material(self, args):
 66        material_types = []
 67        for material in args:
 68            if material._used:
 69                raise AssertionError('Material already used!')
 70            material._used = True
 71            material_class = type(material)
 72
 73            if material_class in Factory._dynamic_classes.values():
 74                separated = material_class.__name__.split('_')
 75                for s in separated:
 76                    cls = globals()[s]
 77                    if cls not in material_types:
 78                        material_types.append(cls)
 79            else:
 80                if material_class not in material_types:
 81                    material_types.append(material_class)
 82
 83        for i in range(len(material_types) - 1):
 84            for j in range(len(material_types) - i - 1):
 85                if material_types[j].__name__ > material_types[j + 1].__name__:
 86                    material_types[j], material_types[j + 1] = material_types[j + 1], material_types[j]
 87
 88        composite_material = "_".join(cls.__name__ for cls in material_types)
 89
 90        if composite_material not in Factory._dynamic_classes:
 91            total_density = 0
 92            for cls in material_types:
 93                total_density += MATERIAL_DENSITIES[cls.__name__]
 94            average_density = total_density / len(material_types)
 95
 96            dynamic_material_class = type(composite_material, (Material,), {})
 97            MATERIAL_DENSITIES[composite_material] = average_density
 98            Factory._dynamic_classes[composite_material] = dynamic_material_class
 99
100        composite_class = Factory._dynamic_classes[composite_material]
101        total_mass = sum(material.mass for material in args)
102        composite_material = composite_class(total_mass)
103        self.materials.append(composite_material)
104        return composite_material
105
106
107    def _create_materials_from_kwargs(self, kwargs):
108        created_materials = []
109        for material_name, mass in kwargs.items():
110            material_class = globals().get(material_name) or Factory._dynamic_classes.get(material_name)
111            if not material_class:
112                raise ValueError('Invalid material!')
113            material_instance = material_class(mass)
114            self.materials.append(material_instance)
115            created_materials.append(material_instance)
116        return tuple(created_materials)
117
118    def can_build(self, volume):
119        available_volume = sum(m.volume for m in self.materials if not m.get_is_used())
120        return available_volume >= volume
121
122    @classmethod
123    def can_build_together(cls, volume):
124        all_materials = [m for factory in cls._existing_factories for m in factory.materials]
125        total_volume = sum(m.volume for m in all_materials if not m.get_is_used())
126        return total_volume >= volume

.....F.F..
======================================================================
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 61, in __call__
return self._create_composite_material(args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 69, in _create_composite_material
raise AssertionError('Material already used!')
AssertionError: Material already used!

======================================================================
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=2)

Дискусия
История
Това решение има само една версия.