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 трябва да се направи итератор клас или може и така както съм го направил. Въпреки че така ако направя два итератора и ако почна да местя единия това ще афектира и другия. Може ли хинт?
|
f | 1 | import re | f | 1 | import re |
2 | from collections import Counter | 2 | from collections import Counter | ||
3 | 3 | ||||
4 | ERROR_MESSAGE = "https://youtu.be/cK7RCMFkT78?si=qHSHaP8zWJvH1lT5" | 4 | ERROR_MESSAGE = "https://youtu.be/cK7RCMFkT78?si=qHSHaP8zWJvH1lT5" | ||
5 | PRESENT_PATTERN = r'(["\'])([a-zA-Z0-9 ]+)\1' | 5 | PRESENT_PATTERN = r'(["\'])([a-zA-Z0-9 ]+)\1' | ||
t | 6 | SIGNATURE_PATTERN = r'\b\d+\b' | t | 6 | SIGNATURE_PATTERN = r'^\s*\d+\s*$' |
7 | NAUGHTY_KID_PRESENT = 'coal' | 7 | NAUGHTY_KID_PRESENT = 'coal' | ||
8 | 8 | ||||
9 | 9 | ||||
10 | class Santa: | 10 | class Santa: | ||
11 | _instance = None | 11 | _instance = None | ||
12 | _desires = dict() | 12 | _desires = dict() | ||
13 | 13 | ||||
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._instance | 17 | return cls._instance | ||
18 | 18 | ||||
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)] = present | 21 | self._desires[id(kid)] = present | ||
22 | 22 | ||||
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)] = present | 26 | self._desires[int(child_id)] = present | ||
27 | 27 | ||||
28 | def __iter__(self): | 28 | def __iter__(self): | ||
29 | self.current_present_index = 0 | 29 | self.current_present_index = 0 | ||
30 | return self | 30 | return self | ||
31 | 31 | ||||
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 += 1 | 35 | self.current_present_index += 1 | ||
36 | return current_present | 36 | return current_present | ||
37 | else: | 37 | else: | ||
38 | raise StopIteration | 38 | raise StopIteration | ||
39 | 39 | ||||
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) | ||
43 | 43 | ||||
44 | def xmas(self): | 44 | def xmas(self): | ||
45 | 45 | ||||
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 += 1 | 48 | kid.christmases += 1 | ||
49 | return | 49 | return | ||
50 | 50 | ||||
51 | popular_present = self._get_popular_present() | 51 | popular_present = self._get_popular_present() | ||
52 | 52 | ||||
53 | for kid in Kid.kids: | 53 | for kid in Kid.kids: | ||
54 | if kid.christmases >= 5: | 54 | if kid.christmases >= 5: | ||
55 | continue | 55 | continue | ||
56 | 56 | ||||
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)]) | ||
63 | 63 | ||||
64 | kid.christmases += 1 | 64 | kid.christmases += 1 | ||
65 | 65 | ||||
66 | self._desires.clear() | 66 | self._desires.clear() | ||
67 | Kid.black_list.clear() | 67 | Kid.black_list.clear() | ||
68 | 68 | ||||
69 | 69 | ||||
70 | def exception_tracking_decorator(func): | 70 | def 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 e | 76 | raise e | ||
77 | 77 | ||||
78 | return wrapper | 78 | return wrapper | ||
79 | 79 | ||||
80 | 80 | ||||
81 | class Kid(type): | 81 | class Kid(type): | ||
82 | kids = set() | 82 | kids = set() | ||
83 | black_list = set() | 83 | black_list = set() | ||
84 | 84 | ||||
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) | ||
88 | 88 | ||||
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) | ||
92 | 92 | ||||
93 | return super().__new__(cls, name, bases, attrs) | 93 | return super().__new__(cls, name, bases, attrs) | ||
94 | 94 | ||||
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 = 0 | 98 | kid.christmases = 0 | ||
99 | return kid | 99 | return kid |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
15.12.2024 14:32
15.12.2024 14:37