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

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

9 точки общо

9 успешни теста
1 неуспешни теста
Код (last commit)

  1class Material:
  2    density = None
  3
  4    def __init__(self, mass):
  5        self.mass = mass
  6        self.used = False
  7
  8    @property
  9    def volume(self):
 10        return self.mass / self.density
 11
 12
 13class Brick(Material):
 14    density = 2000
 15
 16
 17class Concrete(Material):
 18    density = 2500
 19
 20
 21class Stone(Material):
 22    density = 1600
 23
 24
 25class Wood(Material):
 26    density = 600
 27
 28
 29class Steel(Material):
 30    density = 7700
 31
 32
 33class Factory:
 34    current_material_classes = [Brick, Concrete, Stone, Wood, Steel]
 35    factories = []
 36
 37    def __init__(self):
 38        self.generated_materials = []
 39        self.factories.append(self)
 40
 41    def __call__(self, *args, **kwargs):
 42        self._validate_call_input(args, kwargs)
 43        if kwargs:
 44            return self._get_result_from_kwargs(kwargs)
 45        return self._get_result_from_args(args)
 46
 47    def can_build(self, volume):
 48        return self.generated_materials_volume >= volume
 49
 50    @classmethod
 51    def can_build_together(cls, volume):
 52        generated_volume = sum([factory.generated_materials_volume for factory in cls.factories])
 53        return generated_volume >= volume
 54
 55    @property
 56    def generated_materials_volume(self):
 57        return sum([mat.volume for mat in self.generated_materials if not mat.used])
 58
 59    def _get_new_instance(self, base_classes, cls_name, mass):
 60        new_density = sum([base_class.density for base_class in base_classes]) / len(base_classes)
 61        new_cls = type(
 62            cls_name,
 63            (Material,),
 64            {
 65                "density": new_density
 66            }
 67        )
 68        self.current_material_classes.append(new_cls)
 69        instance = new_cls(mass)
 70        self.generated_materials.append(instance)
 71        return instance
 72
 73    @classmethod
 74    def __get_material_class_by_name(cls, name):
 75        for cur in cls.current_material_classes:
 76            if cur.__name__ == name:
 77                return cur
 78        raise ValueError()
 79
 80    @staticmethod
 81    def _validate_call_input(args, kwargs):
 82        if not args and not kwargs:
 83            raise ValueError()
 84        if args and kwargs:
 85            raise ValueError()
 86
 87    def _get_result_from_kwargs(self, kwargs):
 88        result = []
 89        for (current_type_name, mass) in kwargs.items():
 90            result_class = self.__get_material_class_by_name(current_type_name)
 91            instance = result_class(mass)
 92            result.append(instance)
 93            self.generated_materials.append(instance)
 94        return tuple(result)
 95
 96    def _get_result_from_args(self, args):
 97        self._check_for_material_usage(args)
 98        base_classes, new_mass = self._get_new_class_props(args)
 99        cls_name = "_".join([base.__name__ for base in base_classes])
100        try:
101            result_class = self.__get_material_class_by_name(cls_name)
102            instance = result_class(new_mass)
103            self.generated_materials.append(instance)
104            return instance
105        except ValueError:
106            return self._get_new_instance(base_classes, cls_name, new_mass)
107
108    @staticmethod
109    def _check_for_material_usage(materials):
110        for material_instance in materials:
111            if material_instance.used:
112                raise AssertionError()
113            material_instance.used = True
114
115    @classmethod
116    def _get_new_class_props(cls, args):
117        new_base_classes = []
118        mass = 0
119        for instance in args:
120            for base_class_name in instance.__class__.__name__.split('_'):
121                new_base_classes.append(cls.__get_material_class_by_name(base_class_name))
122            mass += instance.mass
123        new_base_classes.sort(key=lambda obj: obj.__name__)
124        return new_base_classes, mass

.....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 45, in __call__
return self._get_result_from_args(args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 97, in _get_result_from_args
self._check_for_material_usage(args)
File "/tmp/solution.py", line 112, in _check_for_material_usage
raise AssertionError()
AssertionError

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

FAILED (failures=1)

Дискусия
Георги Кунчев
21.11.2024 09:38

Добре е да организираш методите на класа си в конкретен ред. Няма строги правила кое след кое да е, но е добре да ги групираш. Събери всички публични неща и ги сложи последни, или първи (не и преди `__init__` разбира се). Останалите неща би било трудно да групираш, защото имаш доста разновидности и може да се окаже, че са подредени по такъв начин, че да трябва да подскачаш нагоре-надолу, докато четеш, но публичните спокойно можеш да отделиш, за да е ясно на хората, които ползват този клас, какви са му публичните интерфейсите, без да ги търсят измежду останалите неща.
История

n1 n
2 
3class Material:1class Material:
4    density = None2    density = None
53
6    def __init__(self, mass):4    def __init__(self, mass):
7        self.mass = mass5        self.mass = mass
8        self.used = False6        self.used = False
97
10    @property8    @property
11    def volume(self):9    def volume(self):
n12        return float(f"{self.mass / self.density: .2f}")  # надявам се това форматиране да искате, че не е обясненоn10        return self.mass / self.density
13 
1411
1512
16class Brick(Material):13class Brick(Material):
17    density = 200014    density = 2000
1815
1916
20class Concrete(Material):17class Concrete(Material):
21    density = 250018    density = 2500
2219
2320
24class Stone(Material):21class Stone(Material):
25    density = 160022    density = 1600
2623
2724
28class Wood(Material):25class Wood(Material):
29    density = 60026    density = 600
3027
3128
32class Steel(Material):29class Steel(Material):
33    density = 770030    density = 7700
3431
3532
n36BASE_MATERIALS = (Brick, Concrete, Stone, Wood, Steel)n
37 
38 
39class Factory:33class Factory:
n40    current_material_classes = list(BASE_MATERIALS).copy()n34    current_material_classes = [Brick, Concrete, Stone, Wood, Steel]
41    factories = []35    factories = []
4236
43    def __init__(self):37    def __init__(self):
44        self.generated_materials = []38        self.generated_materials = []
n45        self.__class__.factories.append(self)n39        self.factories.append(self)
4640
47    def __call__(self, *args, **kwargs):41    def __call__(self, *args, **kwargs):
48        self._validate_call_input(args, kwargs)42        self._validate_call_input(args, kwargs)
49        if kwargs:43        if kwargs:
50            return self._get_result_from_kwargs(kwargs)44            return self._get_result_from_kwargs(kwargs)
n51        return self._get_result_from_args(list(args))n45        return self._get_result_from_args(args)
46 
47    def can_build(self, volume):
48        return self.generated_materials_volume >= volume
49 
50    @classmethod
51    def can_build_together(cls, volume):
52        generated_volume = sum([factory.generated_materials_volume for factory in cls.factories])
53        return generated_volume >= volume
54 
55    @property
56    def generated_materials_volume(self):
57        return sum([mat.volume for mat in self.generated_materials if not mat.used])
5258
53    def _get_new_instance(self, base_classes, cls_name, mass):59    def _get_new_instance(self, base_classes, cls_name, mass):
54        new_density = sum([base_class.density for base_class in base_classes]) / len(base_classes)60        new_density = sum([base_class.density for base_class in base_classes]) / len(base_classes)
55        new_cls = type(61        new_cls = type(
56            cls_name,62            cls_name,
57            (Material,),63            (Material,),
58            {64            {
59                "density": new_density65                "density": new_density
60            }66            }
61        )67        )
n62        self.__class__.current_material_classes.append(new_cls)n68        self.current_material_classes.append(new_cls)
63        instance = new_cls(mass)69        instance = new_cls(mass)
64        self.generated_materials.append(instance)70        self.generated_materials.append(instance)
65        return instance71        return instance
6672
n67    @propertyn
68    def generated_materials_volume(self):
69        return sum([mat.volume for mat in self.generated_materials if not mat.used])
70 
71    def can_build(self, volume):
72        return self.generated_materials_volume >= volume
73 
74    @classmethod73    @classmethod
n75    def can_build_together(cls, volume):n
76        generated_volume = sum([factory.generated_materials_volume for factory in cls.factories])
77        return generated_volume >= volume
78 
79    @classmethod
80    def get_material_class_by_name(cls, name):74    def __get_material_class_by_name(cls, name):
81        for cur in cls.current_material_classes:75        for cur in cls.current_material_classes:
82            if cur.__name__ == name:76            if cur.__name__ == name:
83                return cur77                return cur
84        raise ValueError()78        raise ValueError()
8579
86    @staticmethod80    @staticmethod
87    def _validate_call_input(args, kwargs):81    def _validate_call_input(args, kwargs):
88        if not args and not kwargs:82        if not args and not kwargs:
89            raise ValueError()83            raise ValueError()
90        if args and kwargs:84        if args and kwargs:
91            raise ValueError()85            raise ValueError()
9286
93    def _get_result_from_kwargs(self, kwargs):87    def _get_result_from_kwargs(self, kwargs):
94        result = []88        result = []
95        for (current_type_name, mass) in kwargs.items():89        for (current_type_name, mass) in kwargs.items():
n96            result_class = self.get_material_class_by_name(current_type_name)n90            result_class = self.__get_material_class_by_name(current_type_name)
97            instance = result_class(mass)91            instance = result_class(mass)
98            result.append(instance)92            result.append(instance)
99            self.generated_materials.append(instance)93            self.generated_materials.append(instance)
100        return tuple(result)94        return tuple(result)
10195
102    def _get_result_from_args(self, args):96    def _get_result_from_args(self, args):
103        self._check_for_material_usage(args)97        self._check_for_material_usage(args)
104        base_classes, new_mass = self._get_new_class_props(args)98        base_classes, new_mass = self._get_new_class_props(args)
105        cls_name = "_".join([base.__name__ for base in base_classes])99        cls_name = "_".join([base.__name__ for base in base_classes])
106        try:100        try:
n107            result_class = self.get_material_class_by_name(cls_name)n101            result_class = self.__get_material_class_by_name(cls_name)
108            instance = result_class(new_mass)102            instance = result_class(new_mass)
109            self.generated_materials.append(instance)103            self.generated_materials.append(instance)
110            return instance104            return instance
111        except ValueError:105        except ValueError:
112            return self._get_new_instance(base_classes, cls_name, new_mass)106            return self._get_new_instance(base_classes, cls_name, new_mass)
113107
114    @staticmethod108    @staticmethod
115    def _check_for_material_usage(materials):109    def _check_for_material_usage(materials):
116        for material_instance in materials:110        for material_instance in materials:
117            if material_instance.used:111            if material_instance.used:
118                raise AssertionError()112                raise AssertionError()
119            material_instance.used = True113            material_instance.used = True
120114
nn115    @classmethod
121    def _get_new_class_props(self, args):116    def _get_new_class_props(cls, args):
122        new_base_classes = []117        new_base_classes = []
123        mass = 0118        mass = 0
124        for instance in args:119        for instance in args:
125            for base_class_name in instance.__class__.__name__.split('_'):120            for base_class_name in instance.__class__.__name__.split('_'):
n126                new_base_classes.append(self.get_material_class_by_name(base_class_name))n121                new_base_classes.append(cls.__get_material_class_by_name(base_class_name))
127            mass += instance.mass122            mass += instance.mass
t128        return list(sorted(list(new_base_classes), key=lambda obj: obj.__name__)), masst123        new_base_classes.sort(key=lambda obj: obj.__name__)
129 124        return new_base_classes, mass
130 
131__all__ = [
132    "Brick", "Concrete", "Wood", "Steel", "Stone", "Factory"
133]
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1f1
22
3class Material:3class Material:
4    density = None4    density = None
55
6    def __init__(self, mass):6    def __init__(self, mass):
7        self.mass = mass7        self.mass = mass
8        self.used = False8        self.used = False
99
10    @property10    @property
11    def volume(self):11    def volume(self):
12        return float(f"{self.mass / self.density: .2f}")  # надявам се това форматиране да искате, че не е обяснено12        return float(f"{self.mass / self.density: .2f}")  # надявам се това форматиране да искате, че не е обяснено
1313
1414
1515
16class Brick(Material):16class Brick(Material):
17    density = 200017    density = 2000
1818
1919
20class Concrete(Material):20class Concrete(Material):
21    density = 250021    density = 2500
2222
2323
24class Stone(Material):24class Stone(Material):
25    density = 160025    density = 1600
2626
2727
28class Wood(Material):28class Wood(Material):
29    density = 60029    density = 600
3030
3131
32class Steel(Material):32class Steel(Material):
33    density = 770033    density = 7700
3434
3535
36BASE_MATERIALS = (Brick, Concrete, Stone, Wood, Steel)36BASE_MATERIALS = (Brick, Concrete, Stone, Wood, Steel)
3737
3838
39class Factory:39class Factory:
40    current_material_classes = list(BASE_MATERIALS).copy()40    current_material_classes = list(BASE_MATERIALS).copy()
41    factories = []41    factories = []
4242
43    def __init__(self):43    def __init__(self):
44        self.generated_materials = []44        self.generated_materials = []
45        self.__class__.factories.append(self)45        self.__class__.factories.append(self)
4646
47    def __call__(self, *args, **kwargs):47    def __call__(self, *args, **kwargs):
48        self._validate_call_input(args, kwargs)48        self._validate_call_input(args, kwargs)
49        if kwargs:49        if kwargs:
50            return self._get_result_from_kwargs(kwargs)50            return self._get_result_from_kwargs(kwargs)
51        return self._get_result_from_args(list(args))51        return self._get_result_from_args(list(args))
5252
53    def _get_new_instance(self, base_classes, cls_name, mass):53    def _get_new_instance(self, base_classes, cls_name, mass):
54        new_density = sum([base_class.density for base_class in base_classes]) / len(base_classes)54        new_density = sum([base_class.density for base_class in base_classes]) / len(base_classes)
55        new_cls = type(55        new_cls = type(
56            cls_name,56            cls_name,
57            (Material,),57            (Material,),
58            {58            {
59                "density": new_density59                "density": new_density
60            }60            }
61        )61        )
62        self.__class__.current_material_classes.append(new_cls)62        self.__class__.current_material_classes.append(new_cls)
63        instance = new_cls(mass)63        instance = new_cls(mass)
64        self.generated_materials.append(instance)64        self.generated_materials.append(instance)
65        return instance65        return instance
6666
67    @property67    @property
68    def generated_materials_volume(self):68    def generated_materials_volume(self):
69        return sum([mat.volume for mat in self.generated_materials if not mat.used])69        return sum([mat.volume for mat in self.generated_materials if not mat.used])
7070
71    def can_build(self, volume):71    def can_build(self, volume):
72        return self.generated_materials_volume >= volume72        return self.generated_materials_volume >= volume
7373
74    @classmethod74    @classmethod
75    def can_build_together(cls, volume):75    def can_build_together(cls, volume):
76        generated_volume = sum([factory.generated_materials_volume for factory in cls.factories])76        generated_volume = sum([factory.generated_materials_volume for factory in cls.factories])
t77        print(generated_volume)t
78        return generated_volume >= volume77        return generated_volume >= volume
7978
80    @classmethod79    @classmethod
81    def get_material_class_by_name(cls, name):80    def get_material_class_by_name(cls, name):
82        for cur in cls.current_material_classes:81        for cur in cls.current_material_classes:
83            if cur.__name__ == name:82            if cur.__name__ == name:
84                return cur83                return cur
85        raise ValueError()84        raise ValueError()
8685
87    @staticmethod86    @staticmethod
88    def _validate_call_input(args, kwargs):87    def _validate_call_input(args, kwargs):
89        if not args and not kwargs:88        if not args and not kwargs:
90            raise ValueError()89            raise ValueError()
91        if args and kwargs:90        if args and kwargs:
92            raise ValueError()91            raise ValueError()
9392
94    def _get_result_from_kwargs(self, kwargs):93    def _get_result_from_kwargs(self, kwargs):
95        result = []94        result = []
96        for (current_type_name, mass) in kwargs.items():95        for (current_type_name, mass) in kwargs.items():
97            result_class = self.get_material_class_by_name(current_type_name)96            result_class = self.get_material_class_by_name(current_type_name)
98            instance = result_class(mass)97            instance = result_class(mass)
99            result.append(instance)98            result.append(instance)
100            self.generated_materials.append(instance)99            self.generated_materials.append(instance)
101        return tuple(result)100        return tuple(result)
102101
103    def _get_result_from_args(self, args):102    def _get_result_from_args(self, args):
104        self._check_for_material_usage(args)103        self._check_for_material_usage(args)
105        base_classes, new_mass = self._get_new_class_props(args)104        base_classes, new_mass = self._get_new_class_props(args)
106        cls_name = "_".join([base.__name__ for base in base_classes])105        cls_name = "_".join([base.__name__ for base in base_classes])
107        try:106        try:
108            result_class = self.get_material_class_by_name(cls_name)107            result_class = self.get_material_class_by_name(cls_name)
109            instance = result_class(new_mass)108            instance = result_class(new_mass)
110            self.generated_materials.append(instance)109            self.generated_materials.append(instance)
111            return instance110            return instance
112        except ValueError:111        except ValueError:
113            return self._get_new_instance(base_classes, cls_name, new_mass)112            return self._get_new_instance(base_classes, cls_name, new_mass)
114113
115    @staticmethod114    @staticmethod
116    def _check_for_material_usage(materials):115    def _check_for_material_usage(materials):
117        for material_instance in materials:116        for material_instance in materials:
118            if material_instance.used:117            if material_instance.used:
119                raise AssertionError()118                raise AssertionError()
120            material_instance.used = True119            material_instance.used = True
121120
122    def _get_new_class_props(self, args):121    def _get_new_class_props(self, args):
123        new_base_classes = []122        new_base_classes = []
124        mass = 0123        mass = 0
125        for instance in args:124        for instance in args:
126            for base_class_name in instance.__class__.__name__.split('_'):125            for base_class_name in instance.__class__.__name__.split('_'):
127                new_base_classes.append(self.get_material_class_by_name(base_class_name))126                new_base_classes.append(self.get_material_class_by_name(base_class_name))
128            mass += instance.mass127            mass += instance.mass
129        return list(sorted(list(new_base_classes), key=lambda obj: obj.__name__)), mass128        return list(sorted(list(new_base_classes), key=lambda obj: obj.__name__)), mass
130129
131130
132__all__ = [131__all__ = [
133    "Brick", "Concrete", "Wood", "Steel", "Stone", "Factory"132    "Brick", "Concrete", "Wood", "Steel", "Stone", "Factory"
134]133]
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

nn1 
2 
1class Material:3class Material:
2    density = None4    density = None
n3    _base_materials = []n
45
5    def __init__(self, mass):6    def __init__(self, mass):
6        self.mass = mass7        self.mass = mass
7        self.used = False8        self.used = False
89
9    @property10    @property
10    def volume(self):11    def volume(self):
11        return float(f"{self.mass / self.density: .2f}")  # надявам се това форматиране да искате, че не е обяснено12        return float(f"{self.mass / self.density: .2f}")  # надявам се това форматиране да искате, че не е обяснено
1213
n13    @classmethodn
14    def get_base_materials(cls):
15        if cls in BASE_MATERIALS:
16            return cls._base_materials + [cls]
17        return cls._base_materials
1814
1915
20class Brick(Material):16class Brick(Material):
21    density = 200017    density = 2000
2218
2319
24class Concrete(Material):20class Concrete(Material):
25    density = 250021    density = 2500
2622
2723
28class Stone(Material):24class Stone(Material):
29    density = 160025    density = 1600
3026
3127
32class Wood(Material):28class Wood(Material):
33    density = 60029    density = 600
3430
3531
36class Steel(Material):32class Steel(Material):
37    density = 770033    density = 7700
3834
3935
40BASE_MATERIALS = (Brick, Concrete, Stone, Wood, Steel)36BASE_MATERIALS = (Brick, Concrete, Stone, Wood, Steel)
4137
4238
43class Factory:39class Factory:
44    current_material_classes = list(BASE_MATERIALS).copy()40    current_material_classes = list(BASE_MATERIALS).copy()
45    factories = []41    factories = []
4642
47    def __init__(self):43    def __init__(self):
48        self.generated_materials = []44        self.generated_materials = []
49        self.__class__.factories.append(self)45        self.__class__.factories.append(self)
5046
51    def __call__(self, *args, **kwargs):47    def __call__(self, *args, **kwargs):
52        self._validate_call_input(args, kwargs)48        self._validate_call_input(args, kwargs)
53        if kwargs:49        if kwargs:
54            return self._get_result_from_kwargs(kwargs)50            return self._get_result_from_kwargs(kwargs)
55        return self._get_result_from_args(list(args))51        return self._get_result_from_args(list(args))
5652
57    def _get_new_instance(self, base_classes, cls_name, mass):53    def _get_new_instance(self, base_classes, cls_name, mass):
58        new_density = sum([base_class.density for base_class in base_classes]) / len(base_classes)54        new_density = sum([base_class.density for base_class in base_classes]) / len(base_classes)
59        new_cls = type(55        new_cls = type(
60            cls_name,56            cls_name,
61            (Material,),57            (Material,),
62            {58            {
n63                "density": new_density,n59                "density": new_density
64                "_base_materials": base_classes
65            }60            }
66        )61        )
67        self.__class__.current_material_classes.append(new_cls)62        self.__class__.current_material_classes.append(new_cls)
68        instance = new_cls(mass)63        instance = new_cls(mass)
69        self.generated_materials.append(instance)64        self.generated_materials.append(instance)
70        return instance65        return instance
7166
72    @property67    @property
73    def generated_materials_volume(self):68    def generated_materials_volume(self):
74        return sum([mat.volume for mat in self.generated_materials if not mat.used])69        return sum([mat.volume for mat in self.generated_materials if not mat.used])
7570
76    def can_build(self, volume):71    def can_build(self, volume):
77        return self.generated_materials_volume >= volume72        return self.generated_materials_volume >= volume
7873
79    @classmethod74    @classmethod
80    def can_build_together(cls, volume):75    def can_build_together(cls, volume):
81        generated_volume = sum([factory.generated_materials_volume for factory in cls.factories])76        generated_volume = sum([factory.generated_materials_volume for factory in cls.factories])
nn77        print(generated_volume)
82        return generated_volume > volume78        return generated_volume >= volume
8379
84    @classmethod80    @classmethod
n85    def get_factory_class_by_name(cls, name):n81    def get_material_class_by_name(cls, name):
86        for cur in cls.current_material_classes:82        for cur in cls.current_material_classes:
87            if cur.__name__ == name:83            if cur.__name__ == name:
88                return cur84                return cur
89        raise ValueError()85        raise ValueError()
9086
91    @staticmethod87    @staticmethod
92    def _validate_call_input(args, kwargs):88    def _validate_call_input(args, kwargs):
93        if not args and not kwargs:89        if not args and not kwargs:
94            raise ValueError()90            raise ValueError()
95        if args and kwargs:91        if args and kwargs:
96            raise ValueError()92            raise ValueError()
9793
98    def _get_result_from_kwargs(self, kwargs):94    def _get_result_from_kwargs(self, kwargs):
99        result = []95        result = []
100        for (current_type_name, mass) in kwargs.items():96        for (current_type_name, mass) in kwargs.items():
n101            result_class = self.get_factory_class_by_name(current_type_name)n97            result_class = self.get_material_class_by_name(current_type_name)
102            instance = result_class(mass)98            instance = result_class(mass)
103            result.append(instance)99            result.append(instance)
104            self.generated_materials.append(instance)100            self.generated_materials.append(instance)
105        return tuple(result)101        return tuple(result)
106102
107    def _get_result_from_args(self, args):103    def _get_result_from_args(self, args):
108        self._check_for_material_usage(args)104        self._check_for_material_usage(args)
109        base_classes, new_mass = self._get_new_class_props(args)105        base_classes, new_mass = self._get_new_class_props(args)
110        cls_name = "_".join([base.__name__ for base in base_classes])106        cls_name = "_".join([base.__name__ for base in base_classes])
111        try:107        try:
n112            result_class = self.get_factory_class_by_name(cls_name)n108            result_class = self.get_material_class_by_name(cls_name)
113            instance = result_class(new_mass)109            instance = result_class(new_mass)
114            self.generated_materials.append(instance)110            self.generated_materials.append(instance)
115            return instance111            return instance
116        except ValueError:112        except ValueError:
117            return self._get_new_instance(base_classes, cls_name, new_mass)113            return self._get_new_instance(base_classes, cls_name, new_mass)
118114
119    @staticmethod115    @staticmethod
120    def _check_for_material_usage(materials):116    def _check_for_material_usage(materials):
121        for material_instance in materials:117        for material_instance in materials:
122            if material_instance.used:118            if material_instance.used:
123                raise AssertionError()119                raise AssertionError()
124            material_instance.used = True120            material_instance.used = True
125121
n126    @staticmethodn
127    def _get_new_class_props(args):122    def _get_new_class_props(self, args):
128        new_base_classes = set()123        new_base_classes = []
129        mass = 0124        mass = 0
t130        for cls in args:t125        for instance in args:
131            for base_class in cls.get_base_materials():126            for base_class_name in instance.__class__.__name__.split('_'):
132                new_base_classes.add(base_class)127                new_base_classes.append(self.get_material_class_by_name(base_class_name))
133            mass += cls.mass128            mass += instance.mass
134        return list(sorted(list(new_base_classes), key=lambda obj: obj.__name__)), mass129        return list(sorted(list(new_base_classes), key=lambda obj: obj.__name__)), mass
135130
136131
137__all__ = [132__all__ = [
138    "Brick", "Concrete", "Wood", "Steel", "Stone", "Factory"133    "Brick", "Concrete", "Wood", "Steel", "Stone", "Factory"
139]134]
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1class Material:f1class Material:
2    density = None2    density = None
3    _base_materials = []3    _base_materials = []
44
5    def __init__(self, mass):5    def __init__(self, mass):
6        self.mass = mass6        self.mass = mass
7        self.used = False7        self.used = False
88
9    @property9    @property
10    def volume(self):10    def volume(self):
11        return float(f"{self.mass / self.density: .2f}")  # надявам се това форматиране да искате, че не е обяснено11        return float(f"{self.mass / self.density: .2f}")  # надявам се това форматиране да искате, че не е обяснено
1212
13    @classmethod13    @classmethod
14    def get_base_materials(cls):14    def get_base_materials(cls):
15        if cls in BASE_MATERIALS:15        if cls in BASE_MATERIALS:
16            return cls._base_materials + [cls]16            return cls._base_materials + [cls]
17        return cls._base_materials17        return cls._base_materials
1818
1919
20class Brick(Material):20class Brick(Material):
21    density = 200021    density = 2000
2222
2323
24class Concrete(Material):24class Concrete(Material):
25    density = 250025    density = 2500
2626
2727
28class Stone(Material):28class Stone(Material):
29    density = 160029    density = 1600
3030
3131
32class Wood(Material):32class Wood(Material):
33    density = 60033    density = 600
3434
3535
36class Steel(Material):36class Steel(Material):
37    density = 770037    density = 7700
3838
3939
n40BASE_MATERIALS = [Brick, Concrete, Stone, Wood, Steel]n40BASE_MATERIALS = (Brick, Concrete, Stone, Wood, Steel)
4141
4242
43class Factory:43class Factory:
t44    current_material_classes = BASE_MATERIALS.copy()t44    current_material_classes = list(BASE_MATERIALS).copy()
45    factories = []45    factories = []
4646
47    def __init__(self):47    def __init__(self):
48        self.generated_materials = []48        self.generated_materials = []
49        self.__class__.factories.append(self)49        self.__class__.factories.append(self)
5050
51    def __call__(self, *args, **kwargs):51    def __call__(self, *args, **kwargs):
52        self._validate_call_input(args, kwargs)52        self._validate_call_input(args, kwargs)
53        if kwargs:53        if kwargs:
54            return self._get_result_from_kwargs(kwargs)54            return self._get_result_from_kwargs(kwargs)
55        return self._get_result_from_args(list(args))55        return self._get_result_from_args(list(args))
5656
57    def _get_new_instance(self, base_classes, cls_name, mass):57    def _get_new_instance(self, base_classes, cls_name, mass):
58        new_density = sum([base_class.density for base_class in base_classes]) / len(base_classes)58        new_density = sum([base_class.density for base_class in base_classes]) / len(base_classes)
59        new_cls = type(59        new_cls = type(
60            cls_name,60            cls_name,
61            (Material,),61            (Material,),
62            {62            {
63                "density": new_density,63                "density": new_density,
64                "_base_materials": base_classes64                "_base_materials": base_classes
65            }65            }
66        )66        )
67        self.__class__.current_material_classes.append(new_cls)67        self.__class__.current_material_classes.append(new_cls)
68        instance = new_cls(mass)68        instance = new_cls(mass)
69        self.generated_materials.append(instance)69        self.generated_materials.append(instance)
70        return instance70        return instance
7171
72    @property72    @property
73    def generated_materials_volume(self):73    def generated_materials_volume(self):
74        return sum([mat.volume for mat in self.generated_materials if not mat.used])74        return sum([mat.volume for mat in self.generated_materials if not mat.used])
7575
76    def can_build(self, volume):76    def can_build(self, volume):
77        return self.generated_materials_volume >= volume77        return self.generated_materials_volume >= volume
7878
79    @classmethod79    @classmethod
80    def can_build_together(cls, volume):80    def can_build_together(cls, volume):
81        generated_volume = sum([factory.generated_materials_volume for factory in cls.factories])81        generated_volume = sum([factory.generated_materials_volume for factory in cls.factories])
82        return generated_volume > volume82        return generated_volume > volume
8383
84    @classmethod84    @classmethod
85    def get_factory_class_by_name(cls, name):85    def get_factory_class_by_name(cls, name):
86        for cur in cls.current_material_classes:86        for cur in cls.current_material_classes:
87            if cur.__name__ == name:87            if cur.__name__ == name:
88                return cur88                return cur
89        raise ValueError()89        raise ValueError()
9090
91    @staticmethod91    @staticmethod
92    def _validate_call_input(args, kwargs):92    def _validate_call_input(args, kwargs):
93        if not args and not kwargs:93        if not args and not kwargs:
94            raise ValueError()94            raise ValueError()
95        if args and kwargs:95        if args and kwargs:
96            raise ValueError()96            raise ValueError()
9797
98    def _get_result_from_kwargs(self, kwargs):98    def _get_result_from_kwargs(self, kwargs):
99        result = []99        result = []
100        for (current_type_name, mass) in kwargs.items():100        for (current_type_name, mass) in kwargs.items():
101            result_class = self.get_factory_class_by_name(current_type_name)101            result_class = self.get_factory_class_by_name(current_type_name)
102            instance = result_class(mass)102            instance = result_class(mass)
103            result.append(instance)103            result.append(instance)
104            self.generated_materials.append(instance)104            self.generated_materials.append(instance)
105        return tuple(result)105        return tuple(result)
106106
107    def _get_result_from_args(self, args):107    def _get_result_from_args(self, args):
108        self._check_for_material_usage(args)108        self._check_for_material_usage(args)
109        base_classes, new_mass = self._get_new_class_props(args)109        base_classes, new_mass = self._get_new_class_props(args)
110        cls_name = "_".join([base.__name__ for base in base_classes])110        cls_name = "_".join([base.__name__ for base in base_classes])
111        try:111        try:
112            result_class = self.get_factory_class_by_name(cls_name)112            result_class = self.get_factory_class_by_name(cls_name)
113            instance = result_class(new_mass)113            instance = result_class(new_mass)
114            self.generated_materials.append(instance)114            self.generated_materials.append(instance)
115            return instance115            return instance
116        except ValueError:116        except ValueError:
117            return self._get_new_instance(base_classes, cls_name, new_mass)117            return self._get_new_instance(base_classes, cls_name, new_mass)
118118
119    @staticmethod119    @staticmethod
120    def _check_for_material_usage(materials):120    def _check_for_material_usage(materials):
121        for material_instance in materials:121        for material_instance in materials:
122            if material_instance.used:122            if material_instance.used:
123                raise AssertionError()123                raise AssertionError()
124            material_instance.used = True124            material_instance.used = True
125125
126    @staticmethod126    @staticmethod
127    def _get_new_class_props(args):127    def _get_new_class_props(args):
128        new_base_classes = set()128        new_base_classes = set()
129        mass = 0129        mass = 0
130        for cls in args:130        for cls in args:
131            for base_class in cls.get_base_materials():131            for base_class in cls.get_base_materials():
132                new_base_classes.add(base_class)132                new_base_classes.add(base_class)
133            mass += cls.mass133            mass += cls.mass
134        return list(sorted(list(new_base_classes), key=lambda obj: obj.__name__)), mass134        return list(sorted(list(new_base_classes), key=lambda obj: obj.__name__)), mass
135135
136136
137__all__ = [137__all__ = [
138    "Brick", "Concrete", "Wood", "Steel", "Stone", "Factory"138    "Brick", "Concrete", "Wood", "Steel", "Stone", "Factory"
139]139]
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op