Домашни > Another brick in the wall > Решения > Решението на Николай Стоянов

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

9 точки общо

9 успешни теста
1 неуспешни теста
Код (Оправено)

  1class Material:
  2    """Parent class for all the materials."""
  3
  4    DENSITY = 0
  5
  6    def __init__(self, mass):
  7        self.mass = mass
  8        self.is_used = False
  9        self.BASIC_CLASSES = (type(self),)
 10
 11    @property
 12    def volume(self):
 13        return self.mass / self.DENSITY
 14
 15
 16class Concrete(Material):
 17    """Create concrete with mass, density and volume."""
 18
 19    DENSITY = 2500
 20
 21
 22class Brick(Material):
 23    """Create brick with mass, density and volume."""
 24
 25    DENSITY = 2000
 26
 27
 28class Stone(Material):
 29    """Create stone with mass, density and volume."""
 30
 31    DENSITY = 1600
 32
 33
 34class Wood(Material):
 35    """Create wood with mass, density and volume."""
 36
 37    DENSITY = 600
 38
 39
 40class Steel(Material):
 41    """Create steel with mass, density and volume."""
 42
 43    DENSITY = 7700
 44
 45
 46class Factory:
 47    """Create a factory that is callable."""
 48
 49    MATERIAL_PARENT = Material
 50    all_factories = []
 51
 52    def __init__(self):
 53        self.materials = []
 54        self.all_factories.append(self)
 55
 56    def __call__(self, *args, **kwargs):
 57        if not self.__check_for_valid_input(*args, **kwargs):
 58            raise ValueError('Cannot create factory')
 59
 60        if args:
 61            return self.__create_new_material(*args)
 62        else:
 63            return self.__create_known_materials(**kwargs)
 64
 65    def __check_for_valid_input(self, *args, **kwargs):
 66        return bool(args) ^ bool(kwargs)
 67
 68    def __create_new_material(self, *args):
 69        material_classes = {cls.__name__: cls for cls in self.MATERIAL_PARENT.__subclasses__()}
 70        # create new class name
 71        classes_for_new_material = set()
 72        for inst in args:
 73            if type(inst) not in material_classes.values():
 74                raise ValueError('Invalid material')
 75            if inst.is_used:
 76                raise AssertionError('Material is already used')
 77            classes_for_new_material.update((cls for cls in inst.BASIC_CLASSES if cls not in classes_for_new_material))
 78            inst.is_used = True
 79        classes_for_new_material = list(classes_for_new_material)
 80        classes_for_new_material.sort(key=lambda cls: cls.__name__)
 81        new_class_name = '_'.join((cls.__name__ for cls in classes_for_new_material))
 82
 83        # calculate new mass
 84        mass = sum((inst.mass for inst in args))
 85
 86        # earlier exit if class exists
 87        if new_class_name in material_classes:
 88            new_material = material_classes[new_class_name](mass)
 89            self.materials.append(new_material)
 90            return new_material
 91
 92        # calculate new density
 93        basic_densities = set()
 94        for inst in args:
 95            basic_densities.update(inst.BASIC_CLASSES)
 96        new_density = sum(cls.DENSITY for cls in basic_densities) / len(basic_densities)
 97
 98        # create new class
 99        new_class = type(new_class_name,
100                         (self.MATERIAL_PARENT,),
101                         { 'DENSITY': new_density })
102        new_material = new_class(mass)
103        new_material.BASIC_CLASSES = tuple(classes_for_new_material)
104        self.materials.append(new_material)
105        return new_material
106
107    def __create_known_materials(self, **kwargs):
108        material_classes = {cls.__name__: cls for cls in self.MATERIAL_PARENT.__subclasses__()}
109        new_materials = []
110        for key in kwargs.keys():
111            cls = material_classes.get(key, None)
112            if not cls:
113                raise ValueError('Invalid material name')
114            new_materials.append(cls(kwargs[key]))
115
116        self.materials.extend(new_materials)
117        return tuple(new_materials)
118
119    @property
120    def volume_available(self):
121        return sum(mat.volume for mat in self.materials if not mat.is_used)
122
123    def can_build(self, volume):
124        return self.volume_available >= volume
125
126    @classmethod
127    def can_build_together(cls, volume_to_build):
128        total_volume = sum(fact.volume_available for fact in cls.all_factories)
129        return total_volume >= volume_to_build

.....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_new_material(*args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 76, in __create_new_material
raise AssertionError('Material is already used')
AssertionError: Material is already used

----------------------------------------------------------------------
Ran 10 tests in 0.012s

FAILED (failures=1)

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

f1class Material:f1class Material:
2    """Parent class for all the materials."""2    """Parent class for all the materials."""
33
4    DENSITY = 04    DENSITY = 0
55
6    def __init__(self, mass):6    def __init__(self, mass):
7        self.mass = mass7        self.mass = mass
8        self.is_used = False8        self.is_used = False
nn9        self.BASIC_CLASSES = (type(self),)
910
10    @property11    @property
11    def volume(self):12    def volume(self):
12        return self.mass / self.DENSITY13        return self.mass / self.DENSITY
1314
1415
15class Concrete(Material):16class Concrete(Material):
16    """Create concrete with mass, density and volume."""17    """Create concrete with mass, density and volume."""
1718
18    DENSITY = 250019    DENSITY = 2500
1920
2021
21class Brick(Material):22class Brick(Material):
22    """Create brick with mass, density and volume."""23    """Create brick with mass, density and volume."""
2324
24    DENSITY = 200025    DENSITY = 2000
2526
2627
27class Stone(Material):28class Stone(Material):
28    """Create stone with mass, density and volume."""29    """Create stone with mass, density and volume."""
2930
30    DENSITY = 160031    DENSITY = 1600
3132
3233
33class Wood(Material):34class Wood(Material):
34    """Create wood with mass, density and volume."""35    """Create wood with mass, density and volume."""
3536
36    DENSITY = 60037    DENSITY = 600
3738
3839
39class Steel(Material):40class Steel(Material):
40    """Create steel with mass, density and volume."""41    """Create steel with mass, density and volume."""
4142
42    DENSITY = 770043    DENSITY = 7700
4344
4445
45class Factory:46class Factory:
46    """Create a factory that is callable."""47    """Create a factory that is callable."""
4748
48    MATERIAL_PARENT = Material49    MATERIAL_PARENT = Material
49    all_factories = []50    all_factories = []
5051
51    def __init__(self):52    def __init__(self):
52        self.materials = []53        self.materials = []
53        self.all_factories.append(self)54        self.all_factories.append(self)
5455
55    def __call__(self, *args, **kwargs):56    def __call__(self, *args, **kwargs):
56        if not self.__check_for_valid_input(*args, **kwargs):57        if not self.__check_for_valid_input(*args, **kwargs):
57            raise ValueError('Cannot create factory')58            raise ValueError('Cannot create factory')
5859
59        if args:60        if args:
n60            try:n
61                return self.__create_new_material(*args)61            return self.__create_new_material(*args)
62            except Exception:
63                raise
64        else:62        else:
n65            try:n
66                return self.__init_basic_materials(**kwargs)63            return self.__create_known_materials(**kwargs)
67            except Exception:
68                raise
6964
70    def __check_for_valid_input(self, *args, **kwargs):65    def __check_for_valid_input(self, *args, **kwargs):
n71        len_args = len(args)n
72        len_kwargs = len(kwargs)
73        if bool(len_args) == bool(len_kwargs):66        return bool(args) ^ bool(kwargs)
74            return False
75        return True
7667
77    def __create_new_material(self, *args):68    def __create_new_material(self, *args):
78        material_classes = {cls.__name__: cls for cls in self.MATERIAL_PARENT.__subclasses__()}69        material_classes = {cls.__name__: cls for cls in self.MATERIAL_PARENT.__subclasses__()}
79        # create new class name70        # create new class name
n80        classes_for_new_material = []n71        classes_for_new_material = set()
81        for inst in args:72        for inst in args:
82            if type(inst) not in material_classes.values():73            if type(inst) not in material_classes.values():
83                raise ValueError('Invalid material')74                raise ValueError('Invalid material')
84            if inst.is_used:75            if inst.is_used:
85                raise AssertionError('Material is already used')76                raise AssertionError('Material is already used')
n86            basic_classes = getattr(inst, 'BASIC_CLASSES', None) # if material is customn
87            if basic_classes:
88                classes_for_new_material.extend((cls for cls in basic_classes if cls not in classes_for_new_material))77            classes_for_new_material.update((cls for cls in inst.BASIC_CLASSES if cls not in classes_for_new_material))
89            else:
90                classes_for_new_material.append(type(inst))
91            inst.is_used = True78            inst.is_used = True
nn79        classes_for_new_material = list(classes_for_new_material)
92        classes_for_new_material.sort(key=lambda cls: cls.__name__)80        classes_for_new_material.sort(key=lambda cls: cls.__name__)
93        new_class_name = '_'.join((cls.__name__ for cls in classes_for_new_material))81        new_class_name = '_'.join((cls.__name__ for cls in classes_for_new_material))
9482
95        # calculate new mass83        # calculate new mass
n96        mass = sum((arg.mass for arg in args))n84        mass = sum((inst.mass for inst in args))
9785
98        # earlier exit if class exists86        # earlier exit if class exists
n99        if new_class_name in material_classes.keys():n87        if new_class_name in material_classes:
100            new_material = material_classes[new_class_name](mass)88            new_material = material_classes[new_class_name](mass)
101            self.materials.append(new_material)89            self.materials.append(new_material)
102            return new_material90            return new_material
10391
104        # calculate new density92        # calculate new density
105        basic_densities = set()93        basic_densities = set()
n106        for arg in args:n94        for inst in args:
107            basic_classes = getattr(arg, 'BASIC_CLASSES', None)95            basic_densities.update(inst.BASIC_CLASSES)
108            if basic_classes:  # if material is custom
109                basic_densities.update(basic_classes)
110            else:
111                basic_densities.add(type(arg))
112        new_density = sum(cls.DENSITY for cls in basic_densities) / len(basic_densities)96        new_density = sum(cls.DENSITY for cls in basic_densities) / len(basic_densities)
11397
114        # create new class98        # create new class
115        new_class = type(new_class_name,99        new_class = type(new_class_name,
116                         (self.MATERIAL_PARENT,),100                         (self.MATERIAL_PARENT,),
n117                         {n
118                             'DENSITY': new_density,101                         { 'DENSITY': new_density })
119                             'BASIC_CLASSES': classes_for_new_material
120                         })
121        new_material = new_class(mass)102        new_material = new_class(mass)
nn103        new_material.BASIC_CLASSES = tuple(classes_for_new_material)
122        self.materials.append(new_material)104        self.materials.append(new_material)
123        return new_material105        return new_material
124106
t125    def __init_basic_materials(self, **kwargs):t107    def __create_known_materials(self, **kwargs):
126        material_classes = {cls.__name__: cls for cls in self.MATERIAL_PARENT.__subclasses__()}108        material_classes = {cls.__name__: cls for cls in self.MATERIAL_PARENT.__subclasses__()}
127        new_materials = []109        new_materials = []
128        for key in kwargs.keys():110        for key in kwargs.keys():
129            cls = material_classes.get(key, None)111            cls = material_classes.get(key, None)
130            if not cls:112            if not cls:
131                raise ValueError('Invalid material name')113                raise ValueError('Invalid material name')
132            new_materials.append(cls(kwargs[key]))114            new_materials.append(cls(kwargs[key]))
133115
134        self.materials.extend(new_materials)116        self.materials.extend(new_materials)
135        return tuple(new_materials)117        return tuple(new_materials)
136118
137    @property119    @property
138    def volume_available(self):120    def volume_available(self):
139        return sum(mat.volume for mat in self.materials if not mat.is_used)121        return sum(mat.volume for mat in self.materials if not mat.is_used)
140122
141    def can_build(self, volume):123    def can_build(self, volume):
142        return self.volume_available >= volume124        return self.volume_available >= volume
143125
144    @classmethod126    @classmethod
145    def can_build_together(cls, volume_to_build):127    def can_build_together(cls, volume_to_build):
146        total_volume = sum(fact.volume_available for fact in cls.all_factories)128        total_volume = sum(fact.volume_available for fact in cls.all_factories)
147        return total_volume >= volume_to_build129        return total_volume >= volume_to_build
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op