Предизвикателства > She's a witch!


She's a witch!
Краен срок: 10.11.2023 18:00
Точки: 1

#### Въведение Монти Пайтън са известни с невероятната си логика около определянето дали някой е вещица, или не. Ето доказателство: [![She's a witch!](/media/resources/challenge2.jpg)](https://www.youtube.com/watch?v=zrzMhU_4m-g) "Тъй като вещиците се изгарят на клада, те трябва да са от дърво, тъй като и то гори. Дървесината плува по водата, както и патиците. Следователно, ако жената тежи колкото патица, тя трябва да може да се носи по вода, което означава, че е направена от дърво и следователно трябва да е вещица." Ние искаме подход, чрез който да можем да проверяваме дали инстанции на даден клас са вещици, или не. #### Задача Напишете функция `logic_mixin_factory`, която приема 5 позиционни параметъра: - `mass` от тип `int`, което е масата на една патица; - `mass_attr_name` от тип `str`, което е името на атрибута, който се очаква да държи масата на обектите, които ще тестваме; - `material` от тип `str`, което е дефиницията на материала дърво, така, както се очаква да бъде сетнат на обекти, които ще тестваме; - `material_attr_name` от тип `str`, което е името на атрибута, който се очаква да държи материала, от който са направени обектите, с които ще тестваме; - `float_method_name` от тип `str`, което е името на метода на обектите, с който те евентуално могат да плуват. Функцията трябва да връща миксин клас, който да може да бъде наследен от произволен клас, за чийто инстанции бихме се поинтересували дали са вещици. Миксинът ще въоръжава класовете, които го наследяват, с метод `is_a_witch`, който не приема никакви аргументи и връща `str`, в зависимост от това дали инстанцията, върху коята е извикан, е вещица, или не. Ако е вещица, методът връща "Burn her!". Ако не е, връща "No, but it's a pity, cuz she looks like a witch!" Проверките се правят на база параметрите на функцията `logic_mixin_factory`. - Ако инстанцията, за която извикваме `is_a_witch`, има атрибут с името, подадено на `mass_attr_name`, и стойността зад този атрибут е равна на `mass`, то това е вещица. - Ако инстанцията, за което извикваме `is_a_witch`, има атрибут с името, подадено на `material_attr_name`, и стойността зад този атрибут е равна на `material`, то това е вещица. - Ако инстанцията, за която извикваме `is_a_witch`, има метод с името, подадено на `float_method_name`, то това е вещица. Не искаме да извикваме метода, защото това може да доведе до страничен ефект. Просто искаме да проверим дали има такъв метод. - Ако нито едно от горните не е изпълнено, това не е вещица. #### Примерна употреба ``` LogicMixin = logic_mixin_factory(20, 'mass', 'wood', 'material', 'float') class Woman(LogicMixin): ... woman = Woman() print(woman.is_a_witch()) ```
 1import unittest
 2
 3from solution import *
 4
 5
 6class TestWitchMixinFactory(unittest.TestCase):
 7    """Test the WitchMixinFactory"""
 8
 9    def test_sanity(self):
10        """Sanity test for the Witch factory."""
11        self.assertIsInstance(logic_mixin_factory(20, 'mass', 'wood', 'material', 'float'), type)
12
13
14if __name__ == '__main__':
15    unittest.main()
 1import unittest
 2from unittest.mock import Mock
 3
 4from solution import *
 5
 6
 7def set_instance_attributes(**attribute_dict):
 8    """Dynamically set an __init__ of the decorated class with appropriate values."""
 9    def decorated(cls):
10        def __init__(self):
11            for name, value in attribute_dict.items():
12                setattr(self, name, value)
13        cls.__init__ = __init__
14        return cls
15    return decorated
16    
17
18class TestWitchMixinFactory(unittest.TestCase):
19    """Test the WitchMixinFactory"""
20
21    RESULT_TRUE = "Burn her!"
22    RESULT_FALSE = "No, but it's a pity, cuz she looks like a witch!"
23
24    def test_realcase(self):
25        """Real test for the Witch factory."""
26        LogicMixin = logic_mixin_factory(20, 'mass', 'wood', 'material', 'float')
27
28        @set_instance_attributes()
29        class Nothing(LogicMixin): pass
30        self.assertEqual(Nothing().is_a_witch(), self.RESULT_FALSE)
31
32        @set_instance_attributes(mass=20)
33        class MassTrue(LogicMixin): pass
34        self.assertEqual(MassTrue().is_a_witch(), self.RESULT_TRUE)
35
36        @set_instance_attributes(mass=1)
37        class MassFalse(LogicMixin): pass
38        self.assertEqual(MassFalse().is_a_witch(), self.RESULT_FALSE)
39
40        @set_instance_attributes(material='wood')
41        class MaterialTrue(LogicMixin): pass
42        self.assertEqual(MaterialTrue().is_a_witch(), self.RESULT_TRUE)
43
44        @set_instance_attributes(material='random')
45        class MaterialFalse(LogicMixin): pass
46        self.assertEqual(MaterialFalse().is_a_witch(), self.RESULT_FALSE)
47
48        @set_instance_attributes(float='random')
49        class FloatFalse(LogicMixin): pass
50        self.assertEqual(FloatFalse().is_a_witch(), self.RESULT_FALSE)
51
52        mock = Mock()
53
54        @set_instance_attributes(float=lambda *args, **kwargs: mock())
55        class FloatTrue(LogicMixin): pass
56        self.assertEqual(FloatTrue().is_a_witch(), self.RESULT_TRUE)
57        mock.assert_not_called()
58
59
60if __name__ == '__main__':
61    unittest.main()
Дискусия
Георги Кунчев
10.11.2023 16:17

За атрибути може. За методи - не, тъй като име със стойност `None` няма как да е метод.
Тихомир Божков
10.11.2023 15:18

None може ли да бъде валидна стойност за атрибути или методи?