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

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

9 точки общо

9 успешни теста
1 неуспешни теста
Код

  1class Material:
  2    DENSITY = None
  3    def __init__(self, mass):
  4        self.mass = mass
  5       
  6    @property    
  7    def volume(self):
  8        return self.mass / self.DENSITY
  9    
 10
 11class Concrete(Material):
 12    DENSITY = 2500
 13
 14
 15class Brick(Material):
 16    DENSITY = 2000
 17
 18
 19class Stone(Material):
 20    DENSITY = 1600
 21
 22
 23class Wood(Material):
 24    DENSITY = 600
 25
 26
 27class Steel(Material):
 28    DENSITY = 7700
 29
 30
 31class Factory:
 32    material_classes = {
 33            "Concrete": Concrete,
 34            "Brick": Brick,
 35            "Stone": Stone,
 36            "Wood": Wood,
 37            "Steel": Steel,
 38        }  # Shared across all factories, and here we also add the new created classes
 39    _invalid_instances = set()  # Shared across all factories
 40    _materials_created = []  # Tracks materials created by all factories
 41
 42    def __init__(self):
 43        self.local_materials = []  # Tracks materials created by this factory
 44
 45    def __call__(self, *args, **kwargs):
 46        if args and kwargs:
 47            raise ValueError("Cannot mix positional and named arguments.")
 48
 49        if not args and not kwargs:
 50            raise ValueError("No arguments provided.")
 51
 52        if kwargs:
 53            new_materials = self._handle_named_arguments(kwargs)
 54            # Register created materials
 55            self.local_materials.extend(new_materials)
 56            Factory._materials_created.extend(new_materials)
 57            
 58        else:
 59            new_materials = self._handle_positional_arguments(args)
 60            # Register created materials
 61            self.local_materials.append(new_materials)
 62            Factory._materials_created.append(new_materials)
 63
 64        return new_materials
 65
 66    def _handle_named_arguments(self, kwargs):
 67        result = []
 68        for name, mass in kwargs.items():
 69            not_in_material_classes = name not in Factory.material_classes
 70            
 71
 72            if not_in_material_classes:
 73                raise ValueError(f"Invalid material name: {name}")
 74
 75            material_class = self.material_classes.get(name) 
 76
 77            if material_class is None:
 78                material_class = Factory.material_classes[name]
 79            
 80            result.append(material_class(mass))
 81        return tuple(result)
 82
 83    def _handle_positional_arguments(self, args):
 84        for arg in args:
 85            if arg in Factory._invalid_instances:
 86                raise AssertionError("This material has already been used and is now invalid.")
 87
 88        all_material_names = [
 89            mat_name 
 90            for arg in args 
 91            for mat_name in arg.__class__.__name__.split('_')
 92        ]
 93        all_material_names.sort()
 94        class_name = "_".join(mat_name for mat_name in all_material_names)
 95
 96        if class_name not in Factory.material_classes:
 97            densities = [arg.DENSITY for arg in args]
 98            DENSITY = sum(densities) / len(densities)
 99
100            DynamicMaterial = type(
101                class_name,  
102                (Material,),  
103                {"DENSITY": DENSITY},  
104            )
105            Factory.material_classes[class_name] = DynamicMaterial
106
107        new_class = Factory.material_classes[class_name]
108        total_mass = sum(arg.mass for arg in args)
109
110        # Mark used materials as invalid
111        Factory._invalid_instances.update(args)
112
113        return new_class(total_mass)
114
115    def can_build(self, volume: int) -> bool:
116        total_volume = sum(
117            material.volume 
118            for material in self.local_materials 
119            if material not in Factory._invalid_instances
120        )
121        return total_volume >= volume
122
123    @classmethod
124    def can_build_together(cls, volume: int) -> bool:
125        total_volume = sum(
126            material.volume 
127            for material in cls._materials_created 
128            if material not in cls._invalid_instances
129        )
130        return total_volume >= volume

......F...
======================================================================
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)

----------------------------------------------------------------------
Ran 10 tests in 0.016s

FAILED (failures=1)

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

f1class Material:f1class Material:
nn2    DENSITY = None
2    def __init__(self, mass):3    def __init__(self, mass):
3        self.mass = mass4        self.mass = mass
n4        self.density = Nonen5       
5 
6    @property    6    @property    
7    def volume(self):7    def volume(self):
n8        return self.mass / self.densityn8        return self.mass / self.DENSITY
9    9    
1010
11class Concrete(Material):11class Concrete(Material):
n12    def __init__(self, mass):n12    DENSITY = 2500
13        super().__init__(mass)
14        self.density = 2500
1513
1614
17class Brick(Material):15class Brick(Material):
n18    def __init__(self, mass):n16    DENSITY = 2000
19        super().__init__(mass)
20        self.density = 2000
2117
2218
23class Stone(Material):19class Stone(Material):
n24    def __init__(self, mass):n20    DENSITY = 1600
25        super().__init__(mass)
26        self.density = 1600
2721
2822
29class Wood(Material):23class Wood(Material):
n30    def __init__(self, mass):n24    DENSITY = 600
31        super().__init__(mass)
32        self.density = 600
3325
3426
35class Steel(Material):27class Steel(Material):
n36    def __init__(self, mass):n28    DENSITY = 7700
37        super().__init__(mass)
38        self.density = 7700
3929
4030
41class Factory:31class Factory:
n42    _dynamic_classes = {}  # Shared across all factoriesn
43    _invalid_instances = set()  # Shared across all factories
44    _materials_created = []  # Tracks materials created by all factories
45 
46    def __init__(self):
47        self.material_classes = {32    material_classes = {
48            "Concrete": Concrete,33            "Concrete": Concrete,
49            "Brick": Brick,34            "Brick": Brick,
50            "Stone": Stone,35            "Stone": Stone,
51            "Wood": Wood,36            "Wood": Wood,
52            "Steel": Steel,37            "Steel": Steel,
n53        }n38        }  # Shared across all factories, and here we also add the new created classes
39    _invalid_instances = set()  # Shared across all factories
40    _materials_created = []  # Tracks materials created by all factories
41 
42    def __init__(self):
54        self.local_materials = []  # Tracks materials created by this factory43        self.local_materials = []  # Tracks materials created by this factory
5544
56    def __call__(self, *args, **kwargs):45    def __call__(self, *args, **kwargs):
57        if args and kwargs:46        if args and kwargs:
58            raise ValueError("Cannot mix positional and named arguments.")47            raise ValueError("Cannot mix positional and named arguments.")
5948
60        if not args and not kwargs:49        if not args and not kwargs:
61            raise ValueError("No arguments provided.")50            raise ValueError("No arguments provided.")
6251
63        if kwargs:52        if kwargs:
64            new_materials = self._handle_named_arguments(kwargs)53            new_materials = self._handle_named_arguments(kwargs)
65            # Register created materials54            # Register created materials
66            self.local_materials.extend(new_materials)55            self.local_materials.extend(new_materials)
67            Factory._materials_created.extend(new_materials)56            Factory._materials_created.extend(new_materials)
68            57            
69        else:58        else:
70            new_materials = self._handle_positional_arguments(args)59            new_materials = self._handle_positional_arguments(args)
71            # Register created materials60            # Register created materials
72            self.local_materials.append(new_materials)61            self.local_materials.append(new_materials)
73            Factory._materials_created.append(new_materials)62            Factory._materials_created.append(new_materials)
7463
75        return new_materials64        return new_materials
7665
77    def _handle_named_arguments(self, kwargs):66    def _handle_named_arguments(self, kwargs):
78        result = []67        result = []
79        for name, mass in kwargs.items():68        for name, mass in kwargs.items():
n80            if (n69            not_in_material_classes = name not in Factory.material_classes
81                name not in self.material_classes and 
82                name not in Factory._dynamic_classes
83            ):70            
71 
72            if not_in_material_classes:
84                raise ValueError(f"Invalid material name: {name}")73                raise ValueError(f"Invalid material name: {name}")
8574
86            material_class = self.material_classes.get(name) 75            material_class = self.material_classes.get(name) 
nn76 
87            if material_class is None:77            if material_class is None:
n88                material_class = Factory._dynamic_classes[name]n78                material_class = Factory.material_classes[name]
89            79            
90            result.append(material_class(mass))80            result.append(material_class(mass))
91        return tuple(result)81        return tuple(result)
9282
93    def _handle_positional_arguments(self, args):83    def _handle_positional_arguments(self, args):
94        for arg in args:84        for arg in args:
95            if arg in Factory._invalid_instances:85            if arg in Factory._invalid_instances:
96                raise AssertionError("This material has already been used and is now invalid.")86                raise AssertionError("This material has already been used and is now invalid.")
9787
98        all_material_names = [88        all_material_names = [
99            mat_name 89            mat_name 
100            for arg in args 90            for arg in args 
101            for mat_name in arg.__class__.__name__.split('_')91            for mat_name in arg.__class__.__name__.split('_')
102        ]92        ]
103        all_material_names.sort()93        all_material_names.sort()
104        class_name = "_".join(mat_name for mat_name in all_material_names)94        class_name = "_".join(mat_name for mat_name in all_material_names)
10595
n106        if class_name not in Factory._dynamic_classes:n96        if class_name not in Factory.material_classes:
107            densities = [arg.density for arg in args]97            densities = [arg.DENSITY for arg in args]
108            avg_density = sum(densities) / len(densities)98            DENSITY = sum(densities) / len(densities)
10999
n110            class DynamicMaterial(Material):n100            DynamicMaterial = type(
111                def __init__(self, mass):101                class_name,  
112                    super().__init__(mass)102                (Material,),  
113                    self.density = avg_density   103                {"DENSITY": DENSITY},  
104            )
105            Factory.material_classes[class_name] = DynamicMaterial
114106
t115 t
116            DynamicMaterial.__name__ = class_name
117            Factory._dynamic_classes[class_name] = DynamicMaterial
118 
119        new_class = Factory._dynamic_classes[class_name]107        new_class = Factory.material_classes[class_name]
120        total_mass = sum(arg.mass for arg in args)108        total_mass = sum(arg.mass for arg in args)
121109
122        # Mark used materials as invalid110        # Mark used materials as invalid
123        Factory._invalid_instances.update(args)111        Factory._invalid_instances.update(args)
124112
125        return new_class(total_mass)113        return new_class(total_mass)
126114
127    def can_build(self, volume: int) -> bool:115    def can_build(self, volume: int) -> bool:
128        total_volume = sum(116        total_volume = sum(
129            material.volume 117            material.volume 
130            for material in self.local_materials 118            for material in self.local_materials 
131            if material not in Factory._invalid_instances119            if material not in Factory._invalid_instances
132        )120        )
133        return total_volume >= volume121        return total_volume >= volume
134122
135    @classmethod123    @classmethod
136    def can_build_together(cls, volume: int) -> bool:124    def can_build_together(cls, volume: int) -> bool:
137        total_volume = sum(125        total_volume = sum(
138            material.volume 126            material.volume 
139            for material in cls._materials_created 127            for material in cls._materials_created 
140            if material not in cls._invalid_instances128            if material not in cls._invalid_instances
141        )129        )
142        return total_volume >= volume130        return total_volume >= volume
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op