Домашни > Подаръци ще има за всички от сърце > Решения > Решението на Дейвид Барух

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

7 точки общо

13 успешни теста
7 неуспешни теста
Код

 1import re as re
 2import random
 3
 4PRESENT_PATTERN = r"(['\"])([A-Za-z0-9]+\s*)+\1"
 5SIGNATURE_PATTERN = r"(\s*)\d+\1$"
 6F_KID_YEARS_SANTA = 5
 7BAD_KID = 'coal'
 8
 9class Kid(type):
10    instances = {}
11    def __new__(cls, name, bases, attr_dict):
12        attr_dict["is_naughty"] = False
13        if "__call__" not in attr_dict:
14            raise NotImplementedError(f"Error! Method '__call__' not implemented for this {name}!")
15       
16        return super().__new__(cls, name, bases, attr_dict)
17    
18    def __call__(cls, *args, **kwargs):
19        instance = super().__call__(*args, **kwargs)
20        for method_name in dir(cls):
21            method = getattr(cls, method_name)
22            if not method_name.startswith("_") and callable(method):
23                setattr(instance, method_name, cls._wrap_method(instance, method))                
24
25        cls.instances[id(instance)] = [instance, 0]
26        return instance
27    
28    @staticmethod
29    def _wrap_method(instance, method):
30        def wrapper(*args, **kwargs):
31            try:
32                return method(*args, **kwargs)
33            except Exception as e:
34                instance.is_naughty = True
35        return wrapper
36
37class Santa:
38    __single_instance = None
39    __kids_dict = {}
40
41    def __new__(cls):
42        if cls.__single_instance is None:
43            cls.__single_instance = object().__new__(cls)
44        return cls.__single_instance
45    
46    def __iter__(self):
47        return iter(list(self.__kids_dict.values()))
48    
49    def __get_wish(self, message):
50        present = re.search(PRESENT_PATTERN,message).group()
51        present = re.sub("'", "", present)
52        present = re.sub('"', "", present)
53        return present
54    
55    def __call__(self, kid, wish):
56        present = self.__get_wish(wish)
57        kid_id = id(kid)
58        self.__kids_dict[kid_id] = present
59
60    def __matmul__(self, letter):
61        present = self.__get_wish(letter)
62        match = re.search(SIGNATURE_PATTERN, letter)
63        kid_id = re.sub(" ", "" , match.group())
64        self.__kids_dict[kid_id] = present
65
66    def best_present(self):
67        counts = {}
68        max_occurences = 0
69        presents = list(self.__kids_dict.values())
70        if not presents:
71            return None
72        for present in presents:
73            counts[present] = counts.get(present, 0) + 1
74            max_occurences = max(max_occurences,counts[present])
75        best_presents = [p for p, occurences in counts.items() if occurences == max_occurences]
76        return random.choice(best_presents)
77
78    def xmas(self):
79        best_present = self.best_present()
80       
81        for kid_id, info in Kid.instances.items():          
82            kid, years = info
83            present = self.__kids_dict.get(kid_id, best_present)
84            if years < F_KID_YEARS_SANTA:
85                Kid.instances[kid_id][1] += 1
86                if present:
87                    if kid.is_naughty:
88                        kid(BAD_KID)
89                        kid.is_naughty = False
90                    else:
91                        kid(present)
92               
93        self.__kids_dict = {}

...F..E.E.F.FF...F..
======================================================================
ERROR: test_present_matching (test.TestSanta.test_present_matching)
Test matching signature in the letter.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 78, in test_present_matching
self.santa @ f"""
File "/tmp/solution.py", line 63, in __matmul__
kid_id = re.sub(" ", "" , match.group())
^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'group'

======================================================================
ERROR: test_signature_matching (test.TestSanta.test_signature_matching)
Test matching present in the letter / call.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 100, in test_signature_matching
self.santa @ f"""
File "/tmp/solution.py", line 63, in __matmul__
kid_id = re.sub(" ", "" , match.group())
^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'group'

======================================================================
FAIL: test_call_and_mail_same_kid (test.TestSanta.test_call_and_mail_same_kid)
Test that calls and mails work for the same kid.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 71, in test_call_and_mail_same_kid
self.assertEqual(list(self.santa), ['toy1'])
AssertionError: Lists differ: ['toy1', 'toy1'] != ['toy1']

First list contains 1 additional elements.
First extra element 1:
'toy1'

- ['toy1', 'toy1']
+ ['toy1']

======================================================================
FAIL: test_xmass (test.TestSanta.test_xmass)
Test a simple Christmas case.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 143, in test_xmass
self.assertEqual(kid3.SECRET_PRESENT, 'toy3')
AssertionError: 'toy1' != 'toy3'
- toy1
? ^
+ toy3
? ^

======================================================================
FAIL: test_xmass_kid_without_a_wish (test.TestSanta.test_xmass_kid_without_a_wish)
Test a Christmas with a kids that hasn't sent a wish.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 177, in test_xmass_kid_without_a_wish
self.assertEqual(kid3.SECRET_PRESENT, 'toy2')
AssertionError: 'toy1' != 'toy2'
- toy1
? ^
+ toy2
? ^

======================================================================
FAIL: test_xmass_naughty (test.TestSanta.test_xmass_naughty)
Test a Christmas with naughty kids.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 222, in test_xmass_naughty
with self.assertRaises(ZeroDivisionError):
AssertionError: ZeroDivisionError not raised

======================================================================
FAIL: test_xmass_public_with_no_error (test.TestSanta.test_xmass_public_with_no_error)
Test a Christmas with not-so-naughty kids.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 246, in test_xmass_public_with_no_error
self.assertEqual(kid1.public_without_error(), 42)
AssertionError: None != 42

----------------------------------------------------------------------
Ran 20 tests in 0.031s

FAILED (failures=5, errors=2)

Дискусия
Виктор Бечев
16.12.2024 15:30

`Деца, които са хвърлили изключение в някой от публичните си методи през изминалата година, са непослушни. Вместо подарък, те получават въглен, т.е. са извикани така: kid('coal'). Публичен метод дефинираме като метод, който не започва с долна черта.`
Дейвид Барух
16.12.2024 13:57

Метода винаги ли се казва be_naughty или може да бъде какъвто и да е, просто ако дете викне метод дето дава exception да се маркира като лошо?
Виктор Бечев
15.12.2024 11:54

Можеш да пипаш децата, но нямаш предварителна дефиниция на методите. Така че ще трябва да работиш с някаква абстракция, затова помисли какво се случва, когато бъде достъпен един метод.
Дейвид Барух
14.12.2024 03:00

Може ли насока как да отбелязваме дете като лошо, след като е изпълнен негов 'лош' метод. Не знам до колко трябва да се пипат класовете наследници на Kid, дали може да имат атрибут който да следи дали са лоши и дали може да се сетва когато се вика 'лошия' метод? Малко съм объркан
История

n1import re as rn1import re as re
2import random2import random
33
4PRESENT_PATTERN = r"(['\"])([A-Za-z0-9]+\s*)+\1"4PRESENT_PATTERN = r"(['\"])([A-Za-z0-9]+\s*)+\1"
5SIGNATURE_PATTERN = r"(\s*)\d+\1$"5SIGNATURE_PATTERN = r"(\s*)\d+\1$"
6F_KID_YEARS_SANTA = 56F_KID_YEARS_SANTA = 5
7BAD_KID = 'coal'7BAD_KID = 'coal'
88
9class Kid(type):9class Kid(type):
10    instances = {}10    instances = {}
11    def __new__(cls, name, bases, attr_dict):11    def __new__(cls, name, bases, attr_dict):
n12        attr_dict["bad"] = False n12        attr_dict["is_naughty"] = False
13        if "__call__" not in attr_dict:13        if "__call__" not in attr_dict:
14            raise NotImplementedError(f"Error! Method '__call__' not implemented for this {name}!")14            raise NotImplementedError(f"Error! Method '__call__' not implemented for this {name}!")
nn15       
15        return type.__new__(cls, name, bases, attr_dict)16        return super().__new__(cls, name, bases, attr_dict)
17    
16    def __call__(cls, *args, **kwargs):18    def __call__(cls, *args, **kwargs):
17        instance = super().__call__(*args, **kwargs)19        instance = super().__call__(*args, **kwargs)
nn20        for method_name in dir(cls):
21            method = getattr(cls, method_name)
22            if not method_name.startswith("_") and callable(method):
23                setattr(instance, method_name, cls._wrap_method(instance, method))                
24 
18        cls.instances[id(instance)] = [instance, 0]25        cls.instances[id(instance)] = [instance, 0]
19        return instance26        return instance
n20 n27    
28    @staticmethod
29    def _wrap_method(instance, method):
30        def wrapper(*args, **kwargs):
31            try:
32                return method(*args, **kwargs)
33            except Exception as e:
34                instance.is_naughty = True
35        return wrapper
2136
22class Santa:37class Santa:
23    __single_instance = None38    __single_instance = None
24    __kids_dict = {}39    __kids_dict = {}
2540
26    def __new__(cls):41    def __new__(cls):
27        if cls.__single_instance is None:42        if cls.__single_instance is None:
28            cls.__single_instance = object().__new__(cls)43            cls.__single_instance = object().__new__(cls)
29        return cls.__single_instance44        return cls.__single_instance
30    45    
31    def __iter__(self):46    def __iter__(self):
32        return iter(list(self.__kids_dict.values()))47        return iter(list(self.__kids_dict.values()))
33    48    
n34    def __add_present(self, *args):n49    def __get_wish(self, message):
35        message = args[0]
36        present = r.search(PRESENT_PATTERN,message).group()50        present = re.search(PRESENT_PATTERN,message).group()
37        present = r.sub("'", "", present)51        present = re.sub("'", "", present)
38        present = r.sub('"', "", present)52        present = re.sub('"', "", present)
53        return present
54    
55    def __call__(self, kid, wish):
56        present = self.__get_wish(wish)
39        kid_id = None57        kid_id = id(kid)
40        if len(args) == 2:
41            kid_id = id(args[1])
42        else:
43            match = r.search(SIGNATURE_PATTERN, message)
44            kid_id = r.sub(" ", "" , match.group())
45 
46        self.__kids_dict[kid_id] = present58        self.__kids_dict[kid_id] = present
4759
n48        n60    def __matmul__(self, letter):
49    def __call__(self, kid, wish):61        present = self.__get_wish(letter)
50        self.__add_present(wish, kid)62        match = re.search(SIGNATURE_PATTERN, letter)
63        kid_id = re.sub(" ", "" , match.group())
64        self.__kids_dict[kid_id] = present
5165
n52    def __matmul__(self, letter):n
53        self.__add_present(letter)
54    
55    def best_present(self):66    def best_present(self):
56        counts = {}67        counts = {}
57        max_occurences = 068        max_occurences = 0
58        presents = list(self.__kids_dict.values())69        presents = list(self.__kids_dict.values())
n59        if presents == []:n70        if not presents:
60            return None71            return None
61        for present in presents:72        for present in presents:
62            counts[present] = counts.get(present, 0) + 173            counts[present] = counts.get(present, 0) + 1
63            max_occurences = max(max_occurences,counts[present])74            max_occurences = max(max_occurences,counts[present])
n64        best_presents = [p for p, occs in counts.items() if occs == max_occurences]n75        best_presents = [p for p, occurences in counts.items() if occurences == max_occurences]
65        return random.choice(best_presents)76        return random.choice(best_presents)
6677
67    def xmas(self):78    def xmas(self):
68        best_present = self.best_present()79        best_present = self.best_present()
69       80       
70        for kid_id, info in Kid.instances.items():          81        for kid_id, info in Kid.instances.items():          
n71            kid = info[0]n
72            years = info[1]82            kid, years = info
73            present = self.__kids_dict.get(kid_id, best_present)83            present = self.__kids_dict.get(kid_id, best_present)
74            if years < F_KID_YEARS_SANTA:84            if years < F_KID_YEARS_SANTA:
75                Kid.instances[kid_id][1] += 185                Kid.instances[kid_id][1] += 1
76                if present:86                if present:
nn87                    if kid.is_naughty:
88                        kid(BAD_KID)
89                        kid.is_naughty = False
90                    else:
77                     kid(present)              91                        kid(present)
78               92               
79        self.__kids_dict = {}93        self.__kids_dict = {}
n80 n
81santa = Santa()
8294
8395
8496
8597
8698
8799
88100
tt101 
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op