Домашни > Подаръци ще има за всички от сърце > Решения > Решението на Даниел Стефанов

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

6 точки общо

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

 1import re
 2from collections import Counter
 3
 4ERROR_MESSAGE = "https://youtu.be/cK7RCMFkT78?si=qHSHaP8zWJvH1lT5"
 5PRESENT_PATTERN = r'(["\'])([a-zA-Z0-9 ]+)\1'
 6SIGNATURE_PATTERN = r'^\s*\d+\s*$'
 7NAUGHTY_KID_PRESENT = 'coal'
 8
 9
10class Santa:
11    _instance = None
12    _desires = dict()
13
14    def __new__(cls, *args, **kwargs):
15        if not cls._instance:
16            cls._instance = super().__new__(cls)
17        return cls._instance
18
19    def __call__(self, kid, desire):
20        present = re.search(PRESENT_PATTERN, desire).group(2)
21        self._desires[id(kid)] = present
22
23    def __matmul__(self, letter):
24        present = re.search(PRESENT_PATTERN, letter).group(2)
25        child_id = re.search(SIGNATURE_PATTERN, letter).group(0)
26        self._desires[int(child_id)] = present
27
28    def __iter__(self):
29        self.current_present_index = 0
30        return self
31
32    def __next__(self):
33        if self.current_present_index <= len(self._desires):
34            current_present = self._desires[self.current_present_index]
35            self.current_present_index += 1
36            return current_present
37        else:
38            raise StopIteration
39
40    def _get_popular_present(self):
41        presents_counts = Counter(self._desires.values())
42        return max(presents_counts, key=presents_counts.get)
43
44    def xmas(self):
45
46        if not self._desires:
47            for kid in Kid.kids:
48                kid.christmases += 1
49            return
50
51        popular_present = self._get_popular_present()
52
53        for kid in Kid.kids:
54            if kid.christmases >= 5:
55                continue
56
57            if kid in Kid.black_list:
58                kid(NAUGHTY_KID_PRESENT)
59            elif id(kid) not in self._desires.keys():
60                kid(popular_present)
61            else:
62                kid(self._desires[id(kid)])
63
64            kid.christmases += 1
65
66        self._desires.clear()
67        Kid.black_list.clear()
68
69
70def exception_tracking_decorator(func):
71    def wrapper(self, *args, **kwargs):
72        try:
73            return func(self, *args, **kwargs)
74        except Exception as e:
75            Kid.black_list.add(self)
76            raise e
77
78    return wrapper
79
80
81class Kid(type):
82    kids = set()
83    black_list = set()
84
85    def __new__(cls, name, bases, attrs):
86        if "__call__" not in attrs:
87            raise NotImplementedError(ERROR_MESSAGE)
88
89        for key, value in attrs.items():
90            if hasattr(value, '__call__') and not key.startswith("_"):
91                attrs[key] = exception_tracking_decorator(value)
92
93        return super().__new__(cls, name, bases, attrs)
94
95    def __call__(cls, *args, **kwargs):
96        kid = super().__call__(*args, **kwargs)
97        Kid.kids.add(kid)
98        kid.christmases = 0
99        return kid

..EEEEEEE.E.E.......
======================================================================
ERROR: test_call (test.TestSanta.test_call)
Test sending message via calling.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 56, in test_call
self.assertEqual(list(self.santa), ['toy1', 'toy2'])
^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 34, in __next__
current_present = self._desires[self.current_present_index]
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
KeyError: 0

======================================================================
ERROR: 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 70, in test_call_and_mail_same_kid
self.santa @ f"'toy1'\n{id(kid1)}"
~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
File "/tmp/solution.py", line 25, in __matmul__
child_id = re.search(SIGNATURE_PATTERN, letter).group(0)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'group'

======================================================================
ERROR: test_iterable (test.TestSanta.test_iterable)
Ensure Santa can be iterated multiple times including overwriting presents.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 129, in test_iterable
self.assertEqual(list(self.santa), ['something', 'something else'])
^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 34, in __next__
current_present = self._desires[self.current_present_index]
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
KeyError: 0

======================================================================
ERROR: test_mail (test.TestSanta.test_mail)
Test sending message via email.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 62, in test_mail
self.santa @ f"'toy1'\n{id(kid1)}"
~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
File "/tmp/solution.py", line 25, in __matmul__
child_id = re.search(SIGNATURE_PATTERN, letter).group(0)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'group'

======================================================================
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 25, in __matmul__
child_id = re.search(SIGNATURE_PATTERN, letter).group(0)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'group'

======================================================================
ERROR: test_santa_gift_order (test.TestSanta.test_santa_gift_order)
Test ordering of the Santa iterator.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 256, in test_santa_gift_order
self.santa @ f"'toy3'\n{id(kid3)}"
~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
File "/tmp/solution.py", line 25, in __matmul__
child_id = re.search(SIGNATURE_PATTERN, letter).group(0)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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 25, in __matmul__
child_id = re.search(SIGNATURE_PATTERN, letter).group(0)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'group'

======================================================================
ERROR: test_xmass (test.TestSanta.test_xmass)
Test a simple Christmas case.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 139, in test_xmass
self.santa @ f"'toy3'\n{id(kid3)}"
~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
File "/tmp/solution.py", line 25, in __matmul__
child_id = re.search(SIGNATURE_PATTERN, letter).group(0)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'group'

======================================================================
ERROR: 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 173, in test_xmass_kid_without_a_wish
self.santa @ f"'toy2'\n{id(kid3)}"
~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
File "/tmp/solution.py", line 25, in __matmul__
child_id = re.search(SIGNATURE_PATTERN, letter).group(0)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'group'

----------------------------------------------------------------------
Ran 20 tests in 0.025s

FAILED (errors=9)

Дискусия
Виктор Бечев
15.12.2024 14:54

Отвъд дребните забележки - чист код. Вероятно има миниатюрни неща, които пропускам, но вече достатъчно пъти сме ви казвали за празни редове, кавички и прочие, че да смятаме, че сме си свършили работата в това отношение. И да, видях кавичките. :grin:
Георги Кунчев
13.12.2024 16:46

Не е проблем да направиш итератора директно в класа. Два итератора едва ли някой ще използва.
Даниел Стефанов
13.12.2024 16:41

Не мога да измисля дали за Santa трябва да се направи итератор клас или може и така както съм го направил. Въпреки че така ако направя два итератора и ако почна да местя единия това ще афектира и другия. Може ли хинт?
История

f1import ref1import re
2from collections import Counter2from collections import Counter
33
4ERROR_MESSAGE = "https://youtu.be/cK7RCMFkT78?si=qHSHaP8zWJvH1lT5"4ERROR_MESSAGE = "https://youtu.be/cK7RCMFkT78?si=qHSHaP8zWJvH1lT5"
5PRESENT_PATTERN = r'(["\'])([a-zA-Z0-9 ]+)\1'5PRESENT_PATTERN = r'(["\'])([a-zA-Z0-9 ]+)\1'
t6SIGNATURE_PATTERN = r'\b\d+\b't6SIGNATURE_PATTERN = r'^\s*\d+\s*$'
7NAUGHTY_KID_PRESENT = 'coal'7NAUGHTY_KID_PRESENT = 'coal'
88
99
10class Santa:10class Santa:
11    _instance = None11    _instance = None
12    _desires = dict()12    _desires = dict()
1313
14    def __new__(cls, *args, **kwargs):14    def __new__(cls, *args, **kwargs):
15        if not cls._instance:15        if not cls._instance:
16            cls._instance = super().__new__(cls)16            cls._instance = super().__new__(cls)
17        return cls._instance17        return cls._instance
1818
19    def __call__(self, kid, desire):19    def __call__(self, kid, desire):
20        present = re.search(PRESENT_PATTERN, desire).group(2)20        present = re.search(PRESENT_PATTERN, desire).group(2)
21        self._desires[id(kid)] = present21        self._desires[id(kid)] = present
2222
23    def __matmul__(self, letter):23    def __matmul__(self, letter):
24        present = re.search(PRESENT_PATTERN, letter).group(2)24        present = re.search(PRESENT_PATTERN, letter).group(2)
25        child_id = re.search(SIGNATURE_PATTERN, letter).group(0)25        child_id = re.search(SIGNATURE_PATTERN, letter).group(0)
26        self._desires[int(child_id)] = present26        self._desires[int(child_id)] = present
2727
28    def __iter__(self):28    def __iter__(self):
29        self.current_present_index = 029        self.current_present_index = 0
30        return self30        return self
3131
32    def __next__(self):32    def __next__(self):
33        if self.current_present_index <= len(self._desires):33        if self.current_present_index <= len(self._desires):
34            current_present = self._desires[self.current_present_index]34            current_present = self._desires[self.current_present_index]
35            self.current_present_index += 135            self.current_present_index += 1
36            return current_present36            return current_present
37        else:37        else:
38            raise StopIteration38            raise StopIteration
3939
40    def _get_popular_present(self):40    def _get_popular_present(self):
41        presents_counts = Counter(self._desires.values())41        presents_counts = Counter(self._desires.values())
42        return max(presents_counts, key=presents_counts.get)42        return max(presents_counts, key=presents_counts.get)
4343
44    def xmas(self):44    def xmas(self):
4545
46        if not self._desires:46        if not self._desires:
47            for kid in Kid.kids:47            for kid in Kid.kids:
48                kid.christmases += 148                kid.christmases += 1
49            return49            return
5050
51        popular_present = self._get_popular_present()51        popular_present = self._get_popular_present()
5252
53        for kid in Kid.kids:53        for kid in Kid.kids:
54            if kid.christmases >= 5:54            if kid.christmases >= 5:
55                continue55                continue
5656
57            if kid in Kid.black_list:57            if kid in Kid.black_list:
58                kid(NAUGHTY_KID_PRESENT)58                kid(NAUGHTY_KID_PRESENT)
59            elif id(kid) not in self._desires.keys():59            elif id(kid) not in self._desires.keys():
60                kid(popular_present)60                kid(popular_present)
61            else:61            else:
62                kid(self._desires[id(kid)])62                kid(self._desires[id(kid)])
6363
64            kid.christmases += 164            kid.christmases += 1
6565
66        self._desires.clear()66        self._desires.clear()
67        Kid.black_list.clear()67        Kid.black_list.clear()
6868
6969
70def exception_tracking_decorator(func):70def exception_tracking_decorator(func):
71    def wrapper(self, *args, **kwargs):71    def wrapper(self, *args, **kwargs):
72        try:72        try:
73            return func(self, *args, **kwargs)73            return func(self, *args, **kwargs)
74        except Exception as e:74        except Exception as e:
75            Kid.black_list.add(self)75            Kid.black_list.add(self)
76            raise e76            raise e
7777
78    return wrapper78    return wrapper
7979
8080
81class Kid(type):81class Kid(type):
82    kids = set()82    kids = set()
83    black_list = set()83    black_list = set()
8484
85    def __new__(cls, name, bases, attrs):85    def __new__(cls, name, bases, attrs):
86        if "__call__" not in attrs:86        if "__call__" not in attrs:
87            raise NotImplementedError(ERROR_MESSAGE)87            raise NotImplementedError(ERROR_MESSAGE)
8888
89        for key, value in attrs.items():89        for key, value in attrs.items():
90            if hasattr(value, '__call__') and not key.startswith("_"):90            if hasattr(value, '__call__') and not key.startswith("_"):
91                attrs[key] = exception_tracking_decorator(value)91                attrs[key] = exception_tracking_decorator(value)
9292
93        return super().__new__(cls, name, bases, attrs)93        return super().__new__(cls, name, bases, attrs)
9494
95    def __call__(cls, *args, **kwargs):95    def __call__(cls, *args, **kwargs):
96        kid = super().__call__(*args, **kwargs)96        kid = super().__call__(*args, **kwargs)
97        Kid.kids.add(kid)97        Kid.kids.add(kid)
98        kid.christmases = 098        kid.christmases = 0
99        return kid99        return kid
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op