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

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

6 точки общо

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

  1class Material:
  2    DENSITY = 0
  3
  4    def __init__(self, mass):
  5        self.mass = mass
  6
  7    @property
  8    def volume(self):
  9        return float(self.mass / self.DENSITY)
 10    
 11
 12class Concrete(Material):
 13    DENSITY = 2500
 14
 15
 16class Brick(Material):
 17    DENSITY = 2000
 18
 19
 20class Stone(Material):
 21    DENSITY = 1600
 22
 23
 24class Wood(Material):
 25    DENSITY = 600
 26
 27
 28class Steel(Material):
 29    DENSITY = 7700
 30
 31
 32class Factory:
 33    _MATERIALS = { 
 34        'Concrete': Concrete,
 35        'Brick': Brick,
 36        'Stone': Stone,
 37        'Wood': Wood,
 38        'Steel': Steel
 39        }
 40    
 41    _alloys = {}
 42    _all_materials = set()
 43    _used_materials = set()
 44   
 45    def __init__(self):
 46        self._curr_materials = set()
 47
 48    def __call__(self, *args, **kwargs):
 49        if args and kwargs:
 50            raise ValueError('Function can be called with only positional or only keyword arguments')
 51        elif not args and not kwargs:
 52            raise ValueError('Function cannot be called without arguments')
 53        elif kwargs:
 54            return self._get_result_from_kwargs(**kwargs) 
 55        elif args:
 56            return self._get_alloy_from_args(*args)
 57                
 58    def _get_result_from_kwargs(self, **kwargs):
 59        """Return tuple of instances of materials, created from keyword arguments."""  
 60        res = []
 61        for key, val in kwargs.items():
 62            material = self._MATERIALS.get(key)
 63            if material is None:
 64                material = Factory._alloys.get(key)
 65                
 66            if material is None or not issubclass(material, Material):
 67                raise ValueError('Invalid material')
 68            
 69            new_material = material(val)
 70            Factory._all_materials.add(new_material) 
 71            self._curr_materials.add(new_material)
 72            
 73            res.append(new_material)
 74
 75        return tuple(res)
 76    
 77    def _get_average_density(self, *args):
 78        """Return the average density of the materials."""
 79        density_sum = 0
 80        for arg in args:
 81            density_sum += type(arg).DENSITY
 82        
 83        average_density = density_sum / len(args)
 84        return average_density
 85    
 86    def _get_mass(self, *args):
 87        """Calculate the sum of the masses of the materials"""
 88        mass_sum = 0
 89        for arg in args:
 90            mass_sum += arg.mass
 91
 92        return mass_sum
 93
 94    def _get_alloy_from_args(self, *args):
 95        """Create a dynamic class (alloy) from materials."""
 96        base_classes_names = []
 97
 98        for arg in args:
 99            if arg in Factory._used_materials:
100                raise AssertionError('Invalid material')
101            
102            Factory._used_materials.add(arg)
103            
104            base_classes_names.extend(type(arg).__name__.split('_'))
105            
106        sorted_materials_names = sorted(base_classes_names)
107        new_alloy_name = '_'.join(sorted_materials_names)
108
109        if new_alloy_name not in Factory._alloys:
110            average_density = self._get_average_density(*args)
111            alloy = type(
112                new_alloy_name,
113                  (Material,), 
114                  {'DENSITY': average_density}
115                )
116            Factory._alloys[new_alloy_name] = alloy
117
118        alloy = Factory._alloys[new_alloy_name]
119        alloy_mass = self._get_mass(*args)
120        
121        new_alloy = alloy(alloy_mass)
122        self._curr_materials.add(new_alloy)
123        Factory._all_materials.add(new_alloy)
124        return new_alloy
125        
126    def can_build(self, needed_volume):
127        volume_sum = 0
128        for material in self._curr_materials:
129            if material not in Factory._used_materials:
130                volume_sum += material.volume
131        
132        return volume_sum >= needed_volume
133    
134    @classmethod
135    def can_build_together(cls, needed_volume):
136        volume_sum = 0
137        for material in cls._all_materials:
138            volume_sum += material.volume
139
140        return volume_sum >= needed_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 56, in __call__
return self._get_alloy_from_args(*args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 100, in _get_alloy_from_args
raise AssertionError('Invalid material')
AssertionError: Invalid material

======================================================================
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.020s

FAILED (failures=4)

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

f1class Material:f1class Material:
2    DENSITY = 02    DENSITY = 0
33
4    def __init__(self, mass):4    def __init__(self, mass):
5        self.mass = mass5        self.mass = mass
66
7    @property7    @property
8    def volume(self):8    def volume(self):
9        return float(self.mass / self.DENSITY)9        return float(self.mass / self.DENSITY)
10    10    
1111
12class Concrete(Material):12class Concrete(Material):
13    DENSITY = 250013    DENSITY = 2500
1414
1515
16class Brick(Material):16class Brick(Material):
17    DENSITY = 200017    DENSITY = 2000
1818
1919
20class Stone(Material):20class Stone(Material):
21    DENSITY = 160021    DENSITY = 1600
2222
2323
24class Wood(Material):24class Wood(Material):
25    DENSITY = 60025    DENSITY = 600
2626
2727
28class Steel(Material):28class Steel(Material):
29    DENSITY = 770029    DENSITY = 7700
3030
3131
32class Factory:32class Factory:
33    _MATERIALS = { 33    _MATERIALS = { 
34        'Concrete': Concrete,34        'Concrete': Concrete,
35        'Brick': Brick,35        'Brick': Brick,
36        'Stone': Stone,36        'Stone': Stone,
37        'Wood': Wood,37        'Wood': Wood,
38        'Steel': Steel38        'Steel': Steel
39        }39        }
40    40    
41    _alloys = {}41    _alloys = {}
42    _all_materials = set()42    _all_materials = set()
43    _used_materials = set()43    _used_materials = set()
44   44   
45    def __init__(self):45    def __init__(self):
46        self._curr_materials = set()46        self._curr_materials = set()
4747
48    def __call__(self, *args, **kwargs):48    def __call__(self, *args, **kwargs):
49        if args and kwargs:49        if args and kwargs:
50            raise ValueError('Function can be called with only positional or only keyword arguments')50            raise ValueError('Function can be called with only positional or only keyword arguments')
51        elif not args and not kwargs:51        elif not args and not kwargs:
52            raise ValueError('Function cannot be called without arguments')52            raise ValueError('Function cannot be called without arguments')
53        elif kwargs:53        elif kwargs:
54            return self._get_result_from_kwargs(**kwargs) 54            return self._get_result_from_kwargs(**kwargs) 
55        elif args:55        elif args:
56            return self._get_alloy_from_args(*args)56            return self._get_alloy_from_args(*args)
57                57                
58    def _get_result_from_kwargs(self, **kwargs):58    def _get_result_from_kwargs(self, **kwargs):
n59        """Returns tuple of instances of materials, created from keyword arguments."""  n59        """Return tuple of instances of materials, created from keyword arguments."""  
60        res = []60        res = []
61        for key, val in kwargs.items():61        for key, val in kwargs.items():
62            material = self._MATERIALS.get(key)62            material = self._MATERIALS.get(key)
63            if material is None:63            if material is None:
64                material = Factory._alloys.get(key)64                material = Factory._alloys.get(key)
65                65                
66            if material is None or not issubclass(material, Material):66            if material is None or not issubclass(material, Material):
67                raise ValueError('Invalid material')67                raise ValueError('Invalid material')
68            68            
69            new_material = material(val)69            new_material = material(val)
70            Factory._all_materials.add(new_material) 70            Factory._all_materials.add(new_material) 
71            self._curr_materials.add(new_material)71            self._curr_materials.add(new_material)
72            72            
73            res.append(new_material)73            res.append(new_material)
7474
75        return tuple(res)75        return tuple(res)
76    76    
77    def _get_average_density(self, *args):77    def _get_average_density(self, *args):
n78        """Returns the average density of the materials."""n78        """Return the average density of the materials."""
79        density_sum = 079        density_sum = 0
80        for arg in args:80        for arg in args:
81            density_sum += type(arg).DENSITY81            density_sum += type(arg).DENSITY
82        82        
83        average_density = density_sum / len(args)83        average_density = density_sum / len(args)
84        return average_density84        return average_density
85    85    
86    def _get_mass(self, *args):86    def _get_mass(self, *args):
n87        """Calculates the sum of the masses of the materials"""n87        """Calculate the sum of the masses of the materials"""
88        mass_sum = 088        mass_sum = 0
89        for arg in args:89        for arg in args:
90            mass_sum += arg.mass90            mass_sum += arg.mass
9191
92        return mass_sum92        return mass_sum
9393
94    def _get_alloy_from_args(self, *args):94    def _get_alloy_from_args(self, *args):
t95        """Creates a dynamic class (alloy) from materials."""t95        """Create a dynamic class (alloy) from materials."""
96        base_classes_names = []96        base_classes_names = []
9797
98        for arg in args:98        for arg in args:
99            if arg in Factory._used_materials:99            if arg in Factory._used_materials:
100                raise AssertionError('Invalid material')100                raise AssertionError('Invalid material')
101            101            
102            Factory._used_materials.add(arg)102            Factory._used_materials.add(arg)
103            103            
104            base_classes_names.extend(type(arg).__name__.split('_'))104            base_classes_names.extend(type(arg).__name__.split('_'))
105            105            
106        sorted_materials_names = sorted(base_classes_names)106        sorted_materials_names = sorted(base_classes_names)
107        new_alloy_name = '_'.join(sorted_materials_names)107        new_alloy_name = '_'.join(sorted_materials_names)
108108
109        if new_alloy_name not in Factory._alloys:109        if new_alloy_name not in Factory._alloys:
110            average_density = self._get_average_density(*args)110            average_density = self._get_average_density(*args)
111            alloy = type(111            alloy = type(
112                new_alloy_name,112                new_alloy_name,
113                  (Material,), 113                  (Material,), 
114                  {'DENSITY': average_density}114                  {'DENSITY': average_density}
115                )115                )
116            Factory._alloys[new_alloy_name] = alloy116            Factory._alloys[new_alloy_name] = alloy
117117
118        alloy = Factory._alloys[new_alloy_name]118        alloy = Factory._alloys[new_alloy_name]
119        alloy_mass = self._get_mass(*args)119        alloy_mass = self._get_mass(*args)
120        120        
121        new_alloy = alloy(alloy_mass)121        new_alloy = alloy(alloy_mass)
122        self._curr_materials.add(new_alloy)122        self._curr_materials.add(new_alloy)
123        Factory._all_materials.add(new_alloy)123        Factory._all_materials.add(new_alloy)
124        return new_alloy124        return new_alloy
125        125        
126    def can_build(self, needed_volume):126    def can_build(self, needed_volume):
127        volume_sum = 0127        volume_sum = 0
128        for material in self._curr_materials:128        for material in self._curr_materials:
129            if material not in Factory._used_materials:129            if material not in Factory._used_materials:
130                volume_sum += material.volume130                volume_sum += material.volume
131        131        
132        return volume_sum >= needed_volume132        return volume_sum >= needed_volume
133    133    
134    @classmethod134    @classmethod
135    def can_build_together(cls, needed_volume):135    def can_build_together(cls, needed_volume):
136        volume_sum = 0136        volume_sum = 0
137        for material in cls._all_materials:137        for material in cls._all_materials:
138            volume_sum += material.volume138            volume_sum += material.volume
139139
140        return volume_sum >= needed_volume140        return volume_sum >= needed_volume
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op