Домашни > Another brick in the wall > Решения > Решението на Тихомир Галов

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

9 точки общо

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

  1class Material:
  2    material_classes = {}
  3    material_densities = {}
  4    density = None
  5
  6    def __init__(self, mass):
  7        self.mass = mass
  8        self.valid = True
  9        self._factory = None
 10
 11    @property
 12    def volume(self):
 13        return self.mass / self.density
 14
 15    def get_base_material_names(self):
 16        return {self.__class__.__name__}
 17
 18
 19class Concrete(Material):
 20    density = 2500
 21
 22
 23class Brick(Material):
 24    density = 2000
 25
 26
 27class Stone(Material):
 28    density = 1600
 29
 30
 31class Wood(Material):
 32    density = 600
 33
 34
 35class Steel(Material):
 36    density = 7700
 37
 38
 39for mat_class in [Concrete, Brick, Stone, Wood, Steel]:
 40    Material.material_classes[mat_class.__name__] = mat_class
 41    Material.material_densities[mat_class.__name__] = mat_class.density
 42
 43
 44class Factory:
 45    composite_classes = {}
 46    all_valid_materials = []
 47
 48    def __init__(self):
 49        self.materials = []  # materials created by this factory
 50
 51    def __call__(self, *args, **kwargs):
 52        if (args and kwargs) or (not args and not kwargs):
 53            raise ValueError("Factory must be called with either positional or keyword arguments, not both or none")
 54
 55        if args:  # Create a composite material
 56            for arg in args:
 57                assert isinstance(arg, Material), "All positional arguments must be Material instances"
 58
 59            for arg in args:
 60                assert arg.valid, "Material has already been used"
 61
 62            base_material_names = set()
 63            for arg in args:
 64                base_material_names.update(arg.get_base_material_names())
 65
 66            composite_class_name = '_'.join(sorted(base_material_names))
 67
 68            base_material_densities = [Material.material_densities[name] for name in base_material_names]
 69            density = sum(base_material_densities) / len(base_material_densities)
 70
 71            key = frozenset(base_material_names)  # Use frozenset for hashability
 72            if key in Factory.composite_classes:  # Existing composite class
 73                composite_class = Factory.composite_classes[key]
 74            else:  # Create a new composite class
 75                composite_class = type(composite_class_name, (Material,), {'density': density})
 76                composite_class.base_material_names = base_material_names
 77
 78                def get_base_material_names(self):
 79                    return self.__class__.base_material_names
 80
 81                composite_class.get_base_material_names = get_base_material_names
 82
 83                Factory.composite_classes[key] = composite_class
 84
 85                Material.material_classes[composite_class_name] = composite_class
 86                Material.material_densities[composite_class_name] = density
 87
 88            total_mass = sum(arg.mass for arg in args)
 89            composite_instance = composite_class(total_mass)
 90
 91            for arg in args:
 92                arg.valid = False
 93
 94            composite_instance._factory = self
 95            composite_instance.valid = True
 96
 97            self.materials.append(composite_instance)
 98            Factory.all_valid_materials.append(composite_instance)
 99
100            return composite_instance
101        else:  # Create individual materials
102            materials = []
103            for name, mass in kwargs.items():
104                if name in Material.material_classes:
105                    material_class = Material.material_classes[name]
106                else:
107                    raise ValueError(f"Unknown material {name}")
108
109                instance = material_class(mass)
110                instance.valid = True
111                instance._factory = self
112
113                materials.append(instance)
114                self.materials.append(instance)
115                Factory.all_valid_materials.append(instance)
116
117            return tuple(materials)
118
119    def can_build(self, volume):
120        total_volume = sum(m.volume for m in self.materials if m.valid)
121        return total_volume >= volume
122
123    @classmethod
124    def can_build_together(cls, volume):
125        total_volume = sum(m.volume for m in cls.all_valid_materials if m.valid)
126        return total_volume >= volume

.......F..
======================================================================
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.014s

FAILED (failures=1)

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