Домашни > Another brick in the wall > Решения > Решението на Марина Господинова

Резултати
10 точки от тестове
1 точки от учител

11 точки общо

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

  1class Material:
  2    """Parent class for defining a material."""
  3
  4    _DENSITY = 1
  5    made_of = None
  6
  7    def __init__(self, mass):
  8        self.mass = mass
  9        self.is_valid = True
 10
 11    @property
 12    def volume(self):
 13        return self.mass / self._DENSITY
 14
 15    def invalidate(self):
 16        self.is_valid = False
 17
 18
 19class Concrete(Material):
 20    """Define the material concrete."""
 21
 22    _DENSITY = 2500
 23    made_of = ("Concrete",)
 24
 25
 26class Brick(Material):
 27    """Define the material brick."""
 28
 29    _DENSITY = 2000
 30    made_of = ("Brick",)
 31
 32
 33class Stone(Material):
 34    """Define the material stone."""
 35
 36    _DENSITY = 1600
 37    made_of = ("Stone",)
 38
 39
 40class Wood(Material):
 41    """Define the material wood."""
 42
 43    _DENSITY = 600
 44    made_of = ("Wood",)
 45
 46
 47class Steel(Material):
 48    """Define the material steel."""
 49
 50    _DENSITY = 7700
 51    made_of = ("Steel",)
 52
 53
 54class Factory:
 55    """Factory for material production."""
 56
 57    allowed_materials = {
 58        "Concrete": Concrete,
 59        "Brick": Brick,
 60        "Stone": Stone,
 61        "Wood": Wood,
 62        "Steel": Steel
 63    }
 64
 65    all_created_materials = []
 66
 67    def __init__(self):
 68        self.created_materials = []
 69
 70    def __call__(self, *args, **kwargs):
 71        if args and kwargs:
 72            raise ValueError("Both arguments and keyword arguments cannot be provided.")
 73
 74        if not args and not kwargs:
 75            raise ValueError("What are you trying to do without materials?!")
 76
 77        if kwargs:
 78            try:
 79                materials = tuple(
 80                    self.allowed_materials[name](mass) for name, mass in kwargs.items()
 81                )
 82                self.created_materials.extend(list(materials))
 83                Factory.all_created_materials.extend(list(materials))
 84            except KeyError:
 85                raise ValueError("Material not found!")
 86            return materials
 87
 88        if args:
 89            if not all(isinstance(arg, tuple(self.allowed_materials.values()))
 90                       for arg in args):
 91                raise ValueError("All arguments must be instances of existing materials.")
 92            if not all(arg.is_valid for arg in args):
 93                raise AssertionError("All materials must be unused.")
 94
 95            for arg in args:
 96                arg.invalidate()
 97
 98            material_names = set()
 99            for arg in args:
100                material_names.update(type(arg).made_of)
101            material_names_inorder = sorted(list(material_names))
102            class_name = "_".join(material_names_inorder)
103
104            if class_name in Factory.allowed_materials:
105                alloy_class = Factory.allowed_materials[class_name]
106            else:
107                densities = [self.allowed_materials[name]._DENSITY
108                             for name in material_names]
109                avg_density = sum(densities) / len(densities)
110                class_attributes = {
111                    'made_of': tuple(material_names),
112                    '_DENSITY': avg_density
113                }
114                alloy_class = type(class_name, (Material,), class_attributes)
115                Factory.allowed_materials[class_name] = alloy_class
116
117            new_material = alloy_class(sum(arg.mass for arg in args))
118            self.created_materials.append(new_material)
119            Factory.all_created_materials.append(new_material)
120            return new_material
121
122    def can_build(self, volume):
123        """Check if enough valid materials have been created to build a wall."""
124        total_volume = sum(material.volume for material in self.created_materials
125                           if material.is_valid)
126        return total_volume >= volume
127
128    @classmethod
129    def can_build_together(cls, volume):
130        """Check if enough valid materials have been created across all factories."""
131        total_volume = sum(material.volume for material in cls.all_created_materials
132                           if material.is_valid)
133        return total_volume >= volume

..........
----------------------------------------------------------------------
Ran 10 tests in 0.014s

OK

Дискусия
Виктор Бечев
23.11.2024 22:46

Останалото е доста чисто, браво.
Виктор Бечев
23.11.2024 22:25

Що се отнася до 79-те символа - ние самите сме една идея по-либерални в собствения си код. Стремим се към 79 като генерално правило, защото нерядко води до чисто написан код и ни кара да се замисляме дали не пишем нечетими глупости. Но както в PEP8 пише "A Foolish Consistency is the Hobgoblin of Little Minds", така че ако кодът ще е по-четим с някой друг ред из него, който е 90 или 104 символа - so be it. Що се отнася до разделението по файлове - в този случай не бих казал, че е необходимо. Обхватът на заданието е прекалено малък за да има смисъл. Разделението по файлове следва да става на базата на логически обособени парчета код, както например по време на уъркшопа - entities.py беше файл, в който изсипвахме функционалността, main.py беше файл, в който седеше "енджина", който принтираше по терминала и взимаше вход. При допълнително усложняване на дизайна - различни атаки, магии и прочие - може би би било да разделим различните елементи в различни файлове. За съжаление няма едно правило, по което можем да се водим за всеки проект, така че "логически обособени части" е най-доброто, което мога да ти предложа. С други думи - да нямаме функционалност за генериране на произволни числа, заедно с функционалност за рисуване по екрана, но пък прекаленото раздробяване също не е необходимо _(откъдето всъщност тръгна и въпросът)_.
Марина Господинова
23.11.2024 17:14

Понеже този път се опитах да спазвам повече PEP8, имам въпрос за правилото за 79 символа на ред. Когато изписваме съобщение и то ли трябва да се пренася, дори да е едно цяло изречение, и като цяло има ли изключения за надвишаването на този брой символи? И още нещо - ако можехме да качваме отделни файлове тук (както и за проекта), добра идея ли е базовите класове да бяха отделени в друг файл (за повече четимост, например в проекти по ООП на C++ трябваше абсолютно всеки клас да е разделен в отделен файл)?
История
Това решение има само една версия.