1import re
2from collections import Counter #for the most wanted items
3
4class Singleton(type):
5 def __new__(cls, name, bases, attrs):
6 def singleton_new(cls):
7 if not hasattr(cls, 'instance'):
8 cls.instance = object.__new__(cls)
9 return cls.instance
10 attrs['__new__'] = singleton_new
11 return type.__new__(cls, name, bases, attrs)
12
13def matcher(regex, string):
14 """Да, копирах Ви кода, за да ползвам регулярен израз за желанията"""
15 match = re.search(regex, string)
16 if match is None:
17 return string
18 # match.group(1) to get only the content within the quotes
19 return match.group(1)
20
21def match_wish (wish: str) -> str:
22 """Explanation cuz I feel like it works na magiq malko:"""
23 # [' "] - matches either type of quotation
24 # [A-Za-z0-9 ]+ - matches letters and numbers (1 or more in the interval)
25 # [' "] - matches the closing quotation
26 regex = r'[\'\"]([A-Za-z0-9 ]+)[\'\"]'
27 return matcher(regex, wish)
28
29def match_id(text: str) -> str:
30 """Matches the line that has the kid's id in it """
31 regex = r'^\s*\d+\s*$' # not the biggest fan of these things *crying emoji*
32 # splitting the text into lines so as to search for the one with the id
33 for line in text.splitlines():
34 if re.match(regex, line):
35 return line
36 return text
37
38
39class Kid(type):
40 def __new__(cls, name, bases, attrs):
41 if "__call__" not in attrs:
42 raise NotImplementedError("Shte se grumna, ne e istina kolko gulgo q pisha taq prostotiq")
43 else:
44 new_cls = type.__new__(cls, name, bases, attrs)
45 if not hasattr(new_cls, "_children"):
46 new_cls._children = set()
47 return new_cls
48
49 def __call__(cls, *args, **kwargs):
50 kid_instance = super().__call__(*args, **kwargs)
51 if hasattr(cls, '_children'):
52 cls._children.add(kid_instance)
53 return kid_instance
54
55 @classmethod
56 def check_naughtiness(cls, kid):
57 """testing the public methods to check"""
58 for attr_name in dir(kid):
59 if not attr_name.startswith("_"):
60 attr = getattr(kid, attr_name)
61 if(callable(attr)):
62 try:
63 attr()
64 except Exception:
65 kid._naughty = True
66 break
67
68 @classmethod
69 def level_up_kid(cls, kid_id):
70 """increment the age of the kid on Christmas"""
71 for kid in cls._children:
72 curr_id = id(kid)
73 if (curr_id == kid_id):
74 kid._age += 1
75
76 @classmethod
77 def get_age(cls, kid_id):
78 for kid in cls._children:
79 if id(kid) == kid_id:
80 return kid._age
81 return None
82
83 @classmethod
84 def is_naughty(cls, kid_id):
85 for kid in cls._children:
86 curr_id = id(kid)
87 if(curr_id == kid_id):
88 return kid._naughty
89
90class Santa(metaclass = Singleton):
91 def __init__(self):
92 self.wishes = {} # key->id, value->wish
93 self.most_wanted_gift = Counter()
94
95 def __call__(self, kid, wish: str):
96 present = match_wish(wish)
97 self.wishes[id(kid)] = present
98 self.most_wanted_gift[present] += 1
99
100 def __matmul__(self, letter: str):
101 present = match_wish(letter)
102 kid_id = match_id(letter)
103 self.wishes[kid_id] = present
104 self.most_wanted_gift[present] += 1
105
106 def __iter__(self):
107 # using the iter function so as to create a new iterator every time
108 return iter(self.wishes.values())
109
110 def xmas(self):
111 if not self.wishes:
112 return #dqdo koleda otiva na borsata, nqma rabota, kriza kriza
113 for kid_id in self.wishes.keys():
114 if Kid.get_age(kid_id) >= 5:
115 continue # does not receive a present
116 if Kid.is_naughty(kid_id):
117 kid('coal')
118 else:
119 wish = self.wishes.get(kid_id)
120 if wish:
121 kid(wish)
122 else:
123 if self.most_wanted_gift:
124 most_wanted_gift = self.most_wanted_gift.most_common(1)[0][0] #tova ne go znaeh che taka se pravi
125 kid(most_wanted_gift)
126 Kid.level_up_kid(kid_id)
...F....E.EEEE..EEEE
======================================================================
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 117, in test_signature_matching
self.santa.xmas()
File "/tmp/solution.py", line 114, in xmas
if Kid.get_age(kid_id) >= 5:
^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 78, in get_age
for kid in cls._children:
^^^^^^^^^^^^^
AttributeError: type object 'Kid' has no attribute '_children'
======================================================================
ERROR: test_xmass (test.TestSanta.test_xmass)
Test a simple Christmas case.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 140, in test_xmass
self.santa.xmas()
File "/tmp/solution.py", line 114, in xmas
if Kid.get_age(kid_id) >= 5:
^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 78, in get_age
for kid in cls._children:
^^^^^^^^^^^^^
AttributeError: type object 'Kid' has no attribute '_children'
======================================================================
ERROR: test_xmass_kid_with_multiple_wishes (test.TestSanta.test_xmass_kid_with_multiple_wishes)
Test a Christmas with a kid who sends multiple wishes.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 186, in test_xmass_kid_with_multiple_wishes
self.santa.xmas()
File "/tmp/solution.py", line 114, in xmas
if Kid.get_age(kid_id) >= 5:
^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 78, in get_age
for kid in cls._children:
^^^^^^^^^^^^^
AttributeError: type object 'Kid' has no attribute '_children'
======================================================================
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 174, in test_xmass_kid_without_a_wish
self.santa.xmas()
File "/tmp/solution.py", line 114, in xmas
if Kid.get_age(kid_id) >= 5:
^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 78, in get_age
for kid in cls._children:
^^^^^^^^^^^^^
AttributeError: type object 'Kid' has no attribute '_children'
======================================================================
ERROR: test_xmass_naughty (test.TestSanta.test_xmass_naughty)
Test a Christmas with naughty kids.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 226, in test_xmass_naughty
self.santa.xmas()
File "/tmp/solution.py", line 114, in xmas
if Kid.get_age(kid_id) >= 5:
^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 78, in get_age
for kid in cls._children:
^^^^^^^^^^^^^
AttributeError: type object 'Kid' has no attribute '_children'
======================================================================
ERROR: test_xmass_private_with_error (test.TestSanta.test_xmass_private_with_error)
Test a Christmas with not-so-naughty kids.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 239, in test_xmass_private_with_error
self.santa.xmas()
File "/tmp/solution.py", line 114, in xmas
if Kid.get_age(kid_id) >= 5:
^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 78, in get_age
for kid in cls._children:
^^^^^^^^^^^^^
AttributeError: type object 'Kid' has no attribute '_children'
======================================================================
ERROR: 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 247, in test_xmass_public_with_no_error
self.santa.xmas()
File "/tmp/solution.py", line 114, in xmas
if Kid.get_age(kid_id) >= 5:
^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 78, in get_age
for kid in cls._children:
^^^^^^^^^^^^^
AttributeError: type object 'Kid' has no attribute '_children'
======================================================================
ERROR: test_xmass_years_5_and_over (test.TestSanta.test_xmass_years_5_and_over)
Test with passing years with kid aged 5 and over.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 212, in test_xmass_years_5_and_over
self.santa.xmas() # Christmas 6
^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 114, in xmas
if Kid.get_age(kid_id) >= 5:
^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 78, in get_age
for kid in cls._children:
^^^^^^^^^^^^^
AttributeError: type object 'Kid' has no attribute '_children'
======================================================================
ERROR: test_xmass_years_under_5 (test.TestSanta.test_xmass_years_under_5)
Test with passing years with a kid under 5 years old.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 193, in test_xmass_years_under_5
self.santa.xmas() # Christmas 1
^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 114, in xmas
if Kid.get_age(kid_id) >= 5:
^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 78, in get_age
for kid in cls._children:
^^^^^^^^^^^^^
AttributeError: type object 'Kid' has no attribute '_children'
======================================================================
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']
----------------------------------------------------------------------
Ran 20 tests in 0.033s
FAILED (failures=1, errors=9)
Георги Кунчев
20.12.2024 10:56Класът `Santa` е добре. Класът `Kid` не.
На въпроса ти - дадох малко информация и горе. Можеш да използваш декоратори, за да следиш дали има грешки в публичните методи.
Ако държиш всички създадени деца в някаква колекция, закачена като клас атрибут на `Kid`, ще можеш сама да следиш колко време е минало като отброяваш колко пъти е извикан `xmas`.
Има доста варианти това да се направи. Можеш да видиш моето решение, в което имам клас посредник - елф, който се грици за това. Но не е нужно да имаш посредник. Цялата информация може да се пази и в `Kid`. Посредникът помага да се отделят отговорностите.
|
Екатерина Стоянова
19.12.2024 17:56Знам, че решението е малоумно, но упорито си играех да направя така, че самият метаклас за Децата да се грижи за техните години и това дали са непослушни. Очевидно, не ми се получи, но искам да ви попитам как би трябвало да стане, без да се запазват самите години и списък с непослушните деца от класа на Дядо Коледа?
Благодаря предварително и извинете, че предавам в последния момент, но за жалост съм програмист, който прокрастинира.
|
f | 1 | import re | f | 1 | import re |
2 | from collections import Counter #for the most wanted items | 2 | from collections import Counter #for the most wanted items | ||
3 | 3 | ||||
4 | class Singleton(type): | 4 | class Singleton(type): | ||
5 | def __new__(cls, name, bases, attrs): | 5 | def __new__(cls, name, bases, attrs): | ||
6 | def singleton_new(cls): | 6 | def singleton_new(cls): | ||
7 | if not hasattr(cls, 'instance'): | 7 | if not hasattr(cls, 'instance'): | ||
8 | cls.instance = object.__new__(cls) | 8 | cls.instance = object.__new__(cls) | ||
9 | return cls.instance | 9 | return cls.instance | ||
10 | attrs['__new__'] = singleton_new | 10 | attrs['__new__'] = singleton_new | ||
11 | return type.__new__(cls, name, bases, attrs) | 11 | return type.__new__(cls, name, bases, attrs) | ||
12 | 12 | ||||
13 | def matcher(regex, string): | 13 | def matcher(regex, string): | ||
14 | """Да, копирах Ви кода, за да ползвам регулярен израз за желанията""" | 14 | """Да, копирах Ви кода, за да ползвам регулярен израз за желанията""" | ||
15 | match = re.search(regex, string) | 15 | match = re.search(regex, string) | ||
16 | if match is None: | 16 | if match is None: | ||
17 | return string | 17 | return string | ||
18 | # match.group(1) to get only the content within the quotes | 18 | # match.group(1) to get only the content within the quotes | ||
19 | return match.group(1) | 19 | return match.group(1) | ||
20 | 20 | ||||
21 | def match_wish (wish: str) -> str: | 21 | def match_wish (wish: str) -> str: | ||
22 | """Explanation cuz I feel like it works na magiq malko:""" | 22 | """Explanation cuz I feel like it works na magiq malko:""" | ||
23 | # [' "] - matches either type of quotation | 23 | # [' "] - matches either type of quotation | ||
24 | # [A-Za-z0-9 ]+ - matches letters and numbers (1 or more in the interval) | 24 | # [A-Za-z0-9 ]+ - matches letters and numbers (1 or more in the interval) | ||
25 | # [' "] - matches the closing quotation | 25 | # [' "] - matches the closing quotation | ||
26 | regex = r'[\'\"]([A-Za-z0-9 ]+)[\'\"]' | 26 | regex = r'[\'\"]([A-Za-z0-9 ]+)[\'\"]' | ||
27 | return matcher(regex, wish) | 27 | return matcher(regex, wish) | ||
28 | 28 | ||||
29 | def match_id(text: str) -> str: | 29 | def match_id(text: str) -> str: | ||
30 | """Matches the line that has the kid's id in it """ | 30 | """Matches the line that has the kid's id in it """ | ||
31 | regex = r'^\s*\d+\s*$' # not the biggest fan of these things *crying emoji* | 31 | regex = r'^\s*\d+\s*$' # not the biggest fan of these things *crying emoji* | ||
32 | # splitting the text into lines so as to search for the one with the id | 32 | # splitting the text into lines so as to search for the one with the id | ||
33 | for line in text.splitlines(): | 33 | for line in text.splitlines(): | ||
34 | if re.match(regex, line): | 34 | if re.match(regex, line): | ||
35 | return line | 35 | return line | ||
36 | return text | 36 | return text | ||
37 | 37 | ||||
38 | 38 | ||||
39 | class Kid(type): | 39 | class Kid(type): | ||
40 | def __new__(cls, name, bases, attrs): | 40 | def __new__(cls, name, bases, attrs): | ||
41 | if "__call__" not in attrs: | 41 | if "__call__" not in attrs: | ||
42 | raise NotImplementedError("Shte se grumna, ne e istina kolko gulgo q pisha taq prostotiq") | 42 | raise NotImplementedError("Shte se grumna, ne e istina kolko gulgo q pisha taq prostotiq") | ||
43 | else: | 43 | else: | ||
44 | new_cls = type.__new__(cls, name, bases, attrs) | 44 | new_cls = type.__new__(cls, name, bases, attrs) | ||
45 | if not hasattr(new_cls, "_children"): | 45 | if not hasattr(new_cls, "_children"): | ||
46 | new_cls._children = set() | 46 | new_cls._children = set() | ||
47 | return new_cls | 47 | return new_cls | ||
48 | 48 | ||||
49 | def __call__(cls, *args, **kwargs): | 49 | def __call__(cls, *args, **kwargs): | ||
50 | kid_instance = super().__call__(*args, **kwargs) | 50 | kid_instance = super().__call__(*args, **kwargs) | ||
51 | if hasattr(cls, '_children'): | 51 | if hasattr(cls, '_children'): | ||
52 | cls._children.add(kid_instance) | 52 | cls._children.add(kid_instance) | ||
53 | return kid_instance | 53 | return kid_instance | ||
54 | 54 | ||||
55 | @classmethod | 55 | @classmethod | ||
56 | def check_naughtiness(cls, kid): | 56 | def check_naughtiness(cls, kid): | ||
57 | """testing the public methods to check""" | 57 | """testing the public methods to check""" | ||
58 | for attr_name in dir(kid): | 58 | for attr_name in dir(kid): | ||
59 | if not attr_name.startswith("_"): | 59 | if not attr_name.startswith("_"): | ||
60 | attr = getattr(kid, attr_name) | 60 | attr = getattr(kid, attr_name) | ||
61 | if(callable(attr)): | 61 | if(callable(attr)): | ||
62 | try: | 62 | try: | ||
63 | attr() | 63 | attr() | ||
64 | except Exception: | 64 | except Exception: | ||
65 | kid._naughty = True | 65 | kid._naughty = True | ||
66 | break | 66 | break | ||
67 | 67 | ||||
68 | @classmethod | 68 | @classmethod | ||
69 | def level_up_kid(cls, kid_id): | 69 | def level_up_kid(cls, kid_id): | ||
70 | """increment the age of the kid on Christmas""" | 70 | """increment the age of the kid on Christmas""" | ||
71 | for kid in cls._children: | 71 | for kid in cls._children: | ||
72 | curr_id = id(kid) | 72 | curr_id = id(kid) | ||
73 | if (curr_id == kid_id): | 73 | if (curr_id == kid_id): | ||
74 | kid._age += 1 | 74 | kid._age += 1 | ||
75 | 75 | ||||
76 | @classmethod | 76 | @classmethod | ||
77 | def get_age(cls, kid_id): | 77 | def get_age(cls, kid_id): | ||
78 | for kid in cls._children: | 78 | for kid in cls._children: | ||
79 | if id(kid) == kid_id: | 79 | if id(kid) == kid_id: | ||
80 | return kid._age | 80 | return kid._age | ||
81 | return None | 81 | return None | ||
82 | 82 | ||||
83 | @classmethod | 83 | @classmethod | ||
84 | def is_naughty(cls, kid_id): | 84 | def is_naughty(cls, kid_id): | ||
85 | for kid in cls._children: | 85 | for kid in cls._children: | ||
86 | curr_id = id(kid) | 86 | curr_id = id(kid) | ||
87 | if(curr_id == kid_id): | 87 | if(curr_id == kid_id): | ||
88 | return kid._naughty | 88 | return kid._naughty | ||
89 | 89 | ||||
90 | class Santa(metaclass = Singleton): | 90 | class Santa(metaclass = Singleton): | ||
91 | def __init__(self): | 91 | def __init__(self): | ||
92 | self.wishes = {} # key->id, value->wish | 92 | self.wishes = {} # key->id, value->wish | ||
93 | self.most_wanted_gift = Counter() | 93 | self.most_wanted_gift = Counter() | ||
94 | 94 | ||||
95 | def __call__(self, kid, wish: str): | 95 | def __call__(self, kid, wish: str): | ||
96 | present = match_wish(wish) | 96 | present = match_wish(wish) | ||
97 | self.wishes[id(kid)] = present | 97 | self.wishes[id(kid)] = present | ||
98 | self.most_wanted_gift[present] += 1 | 98 | self.most_wanted_gift[present] += 1 | ||
99 | 99 | ||||
100 | def __matmul__(self, letter: str): | 100 | def __matmul__(self, letter: str): | ||
101 | present = match_wish(letter) | 101 | present = match_wish(letter) | ||
102 | kid_id = match_id(letter) | 102 | kid_id = match_id(letter) | ||
103 | self.wishes[kid_id] = present | 103 | self.wishes[kid_id] = present | ||
104 | self.most_wanted_gift[present] += 1 | 104 | self.most_wanted_gift[present] += 1 | ||
105 | 105 | ||||
106 | def __iter__(self): | 106 | def __iter__(self): | ||
107 | # using the iter function so as to create a new iterator every time | 107 | # using the iter function so as to create a new iterator every time | ||
108 | return iter(self.wishes.values()) | 108 | return iter(self.wishes.values()) | ||
109 | 109 | ||||
110 | def xmas(self): | 110 | def xmas(self): | ||
111 | if not self.wishes: | 111 | if not self.wishes: | ||
112 | return #dqdo koleda otiva na borsata, nqma rabota, kriza kriza | 112 | return #dqdo koleda otiva na borsata, nqma rabota, kriza kriza | ||
113 | for kid_id in self.wishes.keys(): | 113 | for kid_id in self.wishes.keys(): | ||
114 | if Kid.get_age(kid_id) >= 5: | 114 | if Kid.get_age(kid_id) >= 5: | ||
115 | continue # does not receive a present | 115 | continue # does not receive a present | ||
116 | if Kid.is_naughty(kid_id): | 116 | if Kid.is_naughty(kid_id): | ||
117 | kid('coal') | 117 | kid('coal') | ||
118 | else: | 118 | else: | ||
119 | wish = self.wishes.get(kid_id) | 119 | wish = self.wishes.get(kid_id) | ||
120 | if wish: | 120 | if wish: | ||
121 | kid(wish) | 121 | kid(wish) | ||
122 | else: | 122 | else: | ||
123 | if self.most_wanted_gift: | 123 | if self.most_wanted_gift: | ||
124 | most_wanted_gift = self.most_wanted_gift.most_common(1)[0][0] #tova ne go znaeh che taka se pravi | 124 | most_wanted_gift = self.most_wanted_gift.most_common(1)[0][0] #tova ne go znaeh che taka se pravi | ||
125 | kid(most_wanted_gift) | 125 | kid(most_wanted_gift) | ||
126 | Kid.level_up_kid(kid_id) | 126 | Kid.level_up_kid(kid_id) | ||
127 | 127 | ||||
t | 128 | santa = Santa() | t | ||
129 | |||||
130 | |||||
131 | class BulgarianKid(metaclass=Kid): | ||||
132 | |||||
133 | def __call__(self, present): | ||||
134 | self._present = present | ||||
135 | |||||
136 | def be_naughty(self): | ||||
137 | raise RuntimeError('Няма да си изям зеленчуците!') | ||||
138 | |||||
139 | |||||
140 | class ChineseKid(metaclass=Kid): | ||||
141 | |||||
142 | def __call__(self, present): | ||||
143 | self._present = present | ||||
144 | |||||
145 | |||||
146 | goshko = BulgarianKid() | ||||
147 | toshko = BulgarianKid() | ||||
148 | chen = ChineseKid() | ||||
149 | |||||
150 | santa(goshko, "'gun'") | ||||
151 | santa @ f"'gun'\n{id(toshko)}" | ||||
152 | |||||
153 | try: | ||||
154 | goshko.be_naughty() | ||||
155 | except: | ||||
156 | pass | ||||
157 | |||||
158 | santa.xmas() | ||||
159 | # Гошко получава coal | ||||
160 | # Тошко получава gun | ||||
161 | # Chen получава gun | ||||
162 | |||||
163 | santa.xmas() | ||||
164 | # Никой не получава нищо, защото няма желания | ||||
165 | |||||
166 | santa.xmas() | ||||
167 | # Никой не получава нищо, защото няма желания | ||||
168 | |||||
169 | santa.xmas() | ||||
170 | # Никой не получава нищо, защото няма желания | ||||
171 | |||||
172 | gencho = BulgarianKid() | ||||
173 | santa(gencho, "'whistle'") | ||||
174 | |||||
175 | santa.xmas() | ||||
176 | # Всички деца (Гошко, Тошко, Cheng и Генчо) получават whistle | ||||
177 | |||||
178 | kircho = BulgarianKid() | ||||
179 | santa(kircho, "'whistle'") | ||||
180 | |||||
181 | santa.xmas() | ||||
182 | # Кирчо и Генчо получават whistle. Останалите вече са на над 5 години. | ||||
183 | |||||
184 |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
20.12.2024 10:46
20.12.2024 10:46
20.12.2024 10:47
20.12.2024 10:48
19.12.2024 17:58
20.12.2024 10:49
20.12.2024 10:50
20.12.2024 10:51
20.12.2024 10:50
20.12.2024 10:52
20.12.2024 10:52
20.12.2024 10:53