1import re
2
3
4class Singleton(type):
5 _instances = {}
6
7 def __call__(cls, *args, **kwargs):
8 if cls not in cls._instances:
9 cls._instances[cls] = super().__call__(*args, **kwargs)
10 return cls._instances[cls]
11
12
13class Santa(metaclass=Singleton):
14 _MAX_AGE = 5
15
16 def __init__(self):
17 self._wishes = {}
18
19 def _get_wish(self, text):
20 """Get the wish from the letter/call"""
21
22 pattern = r'[\"\']([A-Za-z0-9 ]+)[\"\']'
23 wish = re.search(pattern, text)
24 if wish:
25 return wish.group(1)
26
27 def __call__(self, kid, text):
28 wish = self._get_wish(text)
29 if wish:
30 self._wishes[id(kid)] = wish
31
32 def _get_signature(self, text):
33 """Get the signature of the kid from the letter"""
34
35 pattern = r'\b\d+\b(?=\s*$)'
36 signature = re.search(pattern, text)
37 if signature:
38 return signature.group().strip()
39
40 def __matmul__(self, text):
41 signature = self._get_signature(text)
42 wish = self._get_wish(text)
43 if signature and wish:
44 self._wishes[int(signature)] = wish
45
46 def __iter__(self):
47 for val in self._wishes.values():
48 yield val
49
50 @property
51 def _get_most_wanted_gift(self):
52 """Get the most wanted gift"""
53
54 wishes = list(self._wishes.values())
55 return max(wishes, key=wishes.count)
56
57 def _clear_xmas(self):
58 """Clear the wishes and _naughty_kids"""
59
60 self._wishes.clear()
61 Kid._naughty_kids.clear()
62
63 def xmas(self):
64 Kid._increment_ages()
65
66 if not self._wishes:
67 return
68
69 most_wanted_gift = self._get_most_wanted_gift
70 for identity, kid in Kid._kids_instances.items():
71 if Kid._kids_ages[identity] <= self._MAX_AGE:
72 if kid in Kid._naughty_kids:
73 kid('coal')
74 else:
75 if identity in self._wishes:
76 wish = self._wishes[identity]
77 else:
78 wish = most_wanted_gift
79 kid(wish)
80
81 self._clear_xmas()
82
83
84class Kid(type):
85 _kids_ages = {}
86 _kids_instances = {}
87 _naughty_kids = set()
88
89 @classmethod
90 def _check_naughty(cls, method):
91 def wrapper(self, *args, **kwargs):
92 """Add the instance to _naughty_kids if an exception is raised in method"""
93
94 try:
95 return method(self, *args, **kwargs)
96 except Exception:
97 cls._naughty_kids.add(self)
98 raise
99 return wrapper
100
101 def __new__(cls, name, bases, dct):
102 if '__call__' not in dct:
103 raise NotImplementedError('Sorry, but the instance of the class should be callable (dont get angry, please) :)')
104
105 for attribute_name, attribute_val in dct.items():
106 if callable(attribute_val):
107 if not attribute_name.startswith('_'):
108 dct[attribute_name] = cls._check_naughty(attribute_val)
109
110 return super().__new__(cls, name, bases, dct)
111
112 def __call__(cls, *args, **kwargs):
113 new_kid = super().__call__(*args, **kwargs)
114 identity = id(new_kid)
115 cls._kids_ages[identity] = 0
116 cls._kids_instances[identity] = new_kid
117 return new_kid
118
119 @classmethod
120 def _increment_ages(cls):
121 """Increment the age of each kid by one year"""
122
123 for identity, age in cls._kids_ages.items():
124 cls._kids_ages[identity] += 1
......F.............
======================================================================
FAIL: test_present_matching (test.TestSanta.test_present_matching)
Test matching signature in the letter.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 92, in test_present_matching
self.assertEqual(list(self.santa), ['toy4', 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 '])
AssertionError: Lists differ: ['toy4'] != ['toy4', 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 ']
Second list contains 1 additional elements.
First extra element 1:
'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 '
- ['toy4']
+ ['toy4', 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 ']
----------------------------------------------------------------------
Ran 20 tests in 0.039s
FAILED (failures=1)
f | 1 | import re | f | 1 | import re |
2 | 2 | ||||
3 | 3 | ||||
4 | class Singleton(type): | 4 | class Singleton(type): | ||
5 | _instances = {} | 5 | _instances = {} | ||
6 | 6 | ||||
7 | def __call__(cls, *args, **kwargs): | 7 | def __call__(cls, *args, **kwargs): | ||
8 | if cls not in cls._instances: | 8 | if cls not in cls._instances: | ||
9 | cls._instances[cls] = super().__call__(*args, **kwargs) | 9 | cls._instances[cls] = super().__call__(*args, **kwargs) | ||
10 | return cls._instances[cls] | 10 | return cls._instances[cls] | ||
11 | 11 | ||||
12 | 12 | ||||
13 | class Santa(metaclass=Singleton): | 13 | class Santa(metaclass=Singleton): | ||
n | n | 14 | _MAX_AGE = 5 | ||
15 | |||||
14 | def __init__(self): | 16 | def __init__(self): | ||
15 | self._wishes = {} | 17 | self._wishes = {} | ||
16 | 18 | ||||
17 | def _get_wish(self, text): | 19 | def _get_wish(self, text): | ||
18 | """Get the wish from the letter/call""" | 20 | """Get the wish from the letter/call""" | ||
19 | 21 | ||||
20 | pattern = r'[\"\']([A-Za-z0-9 ]+)[\"\']' | 22 | pattern = r'[\"\']([A-Za-z0-9 ]+)[\"\']' | ||
21 | wish = re.search(pattern, text) | 23 | wish = re.search(pattern, text) | ||
22 | if wish: | 24 | if wish: | ||
23 | return wish.group(1) | 25 | return wish.group(1) | ||
24 | 26 | ||||
25 | def __call__(self, kid, text): | 27 | def __call__(self, kid, text): | ||
26 | wish = self._get_wish(text) | 28 | wish = self._get_wish(text) | ||
27 | if wish: | 29 | if wish: | ||
28 | self._wishes[id(kid)] = wish | 30 | self._wishes[id(kid)] = wish | ||
29 | 31 | ||||
30 | def _get_signature(self, text): | 32 | def _get_signature(self, text): | ||
31 | """Get the signature of the kid from the letter""" | 33 | """Get the signature of the kid from the letter""" | ||
32 | 34 | ||||
33 | pattern = r'\b\d+\b(?=\s*$)' | 35 | pattern = r'\b\d+\b(?=\s*$)' | ||
34 | signature = re.search(pattern, text) | 36 | signature = re.search(pattern, text) | ||
35 | if signature: | 37 | if signature: | ||
36 | return signature.group().strip() | 38 | return signature.group().strip() | ||
37 | 39 | ||||
38 | def __matmul__(self, text): | 40 | def __matmul__(self, text): | ||
39 | signature = self._get_signature(text) | 41 | signature = self._get_signature(text) | ||
40 | wish = self._get_wish(text) | 42 | wish = self._get_wish(text) | ||
41 | if signature and wish: | 43 | if signature and wish: | ||
42 | self._wishes[int(signature)] = wish | 44 | self._wishes[int(signature)] = wish | ||
n | 43 | n | |||
44 | @property | ||||
45 | def _generator(self): | ||||
46 | for key, val in self._wishes.items(): | ||||
47 | yield self._wishes[key] | ||||
48 | 45 | ||||
49 | def __iter__(self): | 46 | def __iter__(self): | ||
n | 50 | return self._generator | n | ||
51 | |||||
52 | def _count_wish_occurence(self, wish): | ||||
53 | """Count the number of times a gift has been wished""" | ||||
54 | |||||
55 | count = 0 | ||||
56 | for key, val in self._wishes.items(): | 47 | for val in self._wishes.values(): | ||
57 | if(val == wish): | 48 | yield val | ||
58 | count += 1 | ||||
59 | return count | ||||
60 | |||||
61 | @property | ||||
62 | def _get_most_wanted_gift_count(self): | ||||
63 | """Get the number of times the most wanted gift has been wished""" | ||||
64 | |||||
65 | max_count = 0 | ||||
66 | for key, val in self._wishes.items(): | ||||
67 | curr_count = self._count_wish_occurence(val) | ||||
68 | if curr_count > max_count: | ||||
69 | max_count = curr_count | ||||
70 | return max_count | ||||
71 | 49 | ||||
72 | @property | 50 | @property | ||
73 | def _get_most_wanted_gift(self): | 51 | def _get_most_wanted_gift(self): | ||
74 | """Get the most wanted gift""" | 52 | """Get the most wanted gift""" | ||
75 | 53 | ||||
n | 76 | most_wanted_gift_count = self._get_most_wanted_gift_count | n | 54 | wishes = list(self._wishes.values()) |
77 | for key, val in self._wishes.items(): | 55 | return max(wishes, key=wishes.count) | ||
78 | if self._count_wish_occurence(val) == most_wanted_gift_count: | ||||
79 | return val | ||||
80 | 56 | ||||
81 | def _clear_xmas(self): | 57 | def _clear_xmas(self): | ||
82 | """Clear the wishes and _naughty_kids""" | 58 | """Clear the wishes and _naughty_kids""" | ||
83 | 59 | ||||
84 | self._wishes.clear() | 60 | self._wishes.clear() | ||
85 | Kid._naughty_kids.clear() | 61 | Kid._naughty_kids.clear() | ||
86 | 62 | ||||
87 | def xmas(self): | 63 | def xmas(self): | ||
88 | Kid._increment_ages() | 64 | Kid._increment_ages() | ||
89 | 65 | ||||
90 | if not self._wishes: | 66 | if not self._wishes: | ||
91 | return | 67 | return | ||
92 | 68 | ||||
93 | most_wanted_gift = self._get_most_wanted_gift | 69 | most_wanted_gift = self._get_most_wanted_gift | ||
94 | for identity, kid in Kid._kids_instances.items(): | 70 | for identity, kid in Kid._kids_instances.items(): | ||
n | 95 | if Kid._kids_ages[identity] <= 5: | n | 71 | if Kid._kids_ages[identity] <= self._MAX_AGE: |
96 | if kid in Kid._naughty_kids: | 72 | if kid in Kid._naughty_kids: | ||
97 | kid('coal') | 73 | kid('coal') | ||
98 | else: | 74 | else: | ||
99 | if identity in self._wishes: | 75 | if identity in self._wishes: | ||
100 | wish = self._wishes[identity] | 76 | wish = self._wishes[identity] | ||
101 | else: | 77 | else: | ||
102 | wish = most_wanted_gift | 78 | wish = most_wanted_gift | ||
103 | kid(wish) | 79 | kid(wish) | ||
104 | 80 | ||||
105 | self._clear_xmas() | 81 | self._clear_xmas() | ||
106 | 82 | ||||
107 | 83 | ||||
108 | class Kid(type): | 84 | class Kid(type): | ||
109 | _kids_ages = {} | 85 | _kids_ages = {} | ||
110 | _kids_instances = {} | 86 | _kids_instances = {} | ||
111 | _naughty_kids = set() | 87 | _naughty_kids = set() | ||
112 | 88 | ||||
113 | @classmethod | 89 | @classmethod | ||
114 | def _check_naughty(cls, method): | 90 | def _check_naughty(cls, method): | ||
115 | def wrapper(self, *args, **kwargs): | 91 | def wrapper(self, *args, **kwargs): | ||
116 | """Add the instance to _naughty_kids if an exception is raised in method""" | 92 | """Add the instance to _naughty_kids if an exception is raised in method""" | ||
117 | 93 | ||||
118 | try: | 94 | try: | ||
119 | return method(self, *args, **kwargs) | 95 | return method(self, *args, **kwargs) | ||
120 | except Exception: | 96 | except Exception: | ||
121 | cls._naughty_kids.add(self) | 97 | cls._naughty_kids.add(self) | ||
122 | raise | 98 | raise | ||
123 | return wrapper | 99 | return wrapper | ||
124 | 100 | ||||
125 | def __new__(cls, name, bases, dct): | 101 | def __new__(cls, name, bases, dct): | ||
126 | if '__call__' not in dct: | 102 | if '__call__' not in dct: | ||
127 | raise NotImplementedError('Sorry, but the instance of the class should be callable (dont get angry, please) :)') | 103 | raise NotImplementedError('Sorry, but the instance of the class should be callable (dont get angry, please) :)') | ||
128 | 104 | ||||
129 | for attribute_name, attribute_val in dct.items(): | 105 | for attribute_name, attribute_val in dct.items(): | ||
t | 130 | if hasattr(attribute_val, '__call__'): | t | 106 | if callable(attribute_val): |
131 | if not attribute_name.startswith('_'): | 107 | if not attribute_name.startswith('_'): | ||
132 | dct[attribute_name] = cls._check_naughty(attribute_val) | 108 | dct[attribute_name] = cls._check_naughty(attribute_val) | ||
133 | 109 | ||||
134 | return super().__new__(cls, name, bases, dct) | 110 | return super().__new__(cls, name, bases, dct) | ||
135 | 111 | ||||
136 | def __call__(cls, *args, **kwargs): | 112 | def __call__(cls, *args, **kwargs): | ||
137 | new_kid = super().__call__(*args, **kwargs) | 113 | new_kid = super().__call__(*args, **kwargs) | ||
138 | identity = id(new_kid) | 114 | identity = id(new_kid) | ||
139 | cls._kids_ages[identity] = 0 | 115 | cls._kids_ages[identity] = 0 | ||
140 | cls._kids_instances[identity] = new_kid | 116 | cls._kids_instances[identity] = new_kid | ||
141 | return new_kid | 117 | return new_kid | ||
142 | 118 | ||||
143 | @classmethod | 119 | @classmethod | ||
144 | def _increment_ages(cls): | 120 | def _increment_ages(cls): | ||
145 | """Increment the age of each kid by one year""" | 121 | """Increment the age of each kid by one year""" | ||
146 | 122 | ||||
147 | for identity, age in cls._kids_ages.items(): | 123 | for identity, age in cls._kids_ages.items(): | ||
148 | cls._kids_ages[identity] += 1 | 124 | cls._kids_ages[identity] += 1 |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | import re | f | 1 | import re |
2 | 2 | ||||
3 | 3 | ||||
4 | class Singleton(type): | 4 | class Singleton(type): | ||
5 | _instances = {} | 5 | _instances = {} | ||
6 | 6 | ||||
7 | def __call__(cls, *args, **kwargs): | 7 | def __call__(cls, *args, **kwargs): | ||
8 | if cls not in cls._instances: | 8 | if cls not in cls._instances: | ||
9 | cls._instances[cls] = super().__call__(*args, **kwargs) | 9 | cls._instances[cls] = super().__call__(*args, **kwargs) | ||
10 | return cls._instances[cls] | 10 | return cls._instances[cls] | ||
11 | 11 | ||||
12 | 12 | ||||
13 | class Santa(metaclass=Singleton): | 13 | class Santa(metaclass=Singleton): | ||
14 | def __init__(self): | 14 | def __init__(self): | ||
15 | self._wishes = {} | 15 | self._wishes = {} | ||
16 | 16 | ||||
17 | def _get_wish(self, text): | 17 | def _get_wish(self, text): | ||
18 | """Get the wish from the letter/call""" | 18 | """Get the wish from the letter/call""" | ||
19 | 19 | ||||
20 | pattern = r'[\"\']([A-Za-z0-9 ]+)[\"\']' | 20 | pattern = r'[\"\']([A-Za-z0-9 ]+)[\"\']' | ||
21 | wish = re.search(pattern, text) | 21 | wish = re.search(pattern, text) | ||
22 | if wish: | 22 | if wish: | ||
23 | return wish.group(1) | 23 | return wish.group(1) | ||
24 | 24 | ||||
25 | def __call__(self, kid, text): | 25 | def __call__(self, kid, text): | ||
26 | wish = self._get_wish(text) | 26 | wish = self._get_wish(text) | ||
27 | if wish: | 27 | if wish: | ||
28 | self._wishes[id(kid)] = wish | 28 | self._wishes[id(kid)] = wish | ||
29 | 29 | ||||
30 | def _get_signature(self, text): | 30 | def _get_signature(self, text): | ||
31 | """Get the signature of the kid from the letter""" | 31 | """Get the signature of the kid from the letter""" | ||
32 | 32 | ||||
33 | pattern = r'\b\d+\b(?=\s*$)' | 33 | pattern = r'\b\d+\b(?=\s*$)' | ||
34 | signature = re.search(pattern, text) | 34 | signature = re.search(pattern, text) | ||
35 | if signature: | 35 | if signature: | ||
36 | return signature.group().strip() | 36 | return signature.group().strip() | ||
37 | 37 | ||||
38 | def __matmul__(self, text): | 38 | def __matmul__(self, text): | ||
39 | signature = self._get_signature(text) | 39 | signature = self._get_signature(text) | ||
40 | wish = self._get_wish(text) | 40 | wish = self._get_wish(text) | ||
41 | if signature and wish: | 41 | if signature and wish: | ||
42 | self._wishes[int(signature)] = wish | 42 | self._wishes[int(signature)] = wish | ||
43 | 43 | ||||
44 | @property | 44 | @property | ||
45 | def _generator(self): | 45 | def _generator(self): | ||
46 | for key, val in self._wishes.items(): | 46 | for key, val in self._wishes.items(): | ||
47 | yield self._wishes[key] | 47 | yield self._wishes[key] | ||
48 | 48 | ||||
49 | def __iter__(self): | 49 | def __iter__(self): | ||
50 | return self._generator | 50 | return self._generator | ||
51 | 51 | ||||
52 | def _count_wish_occurence(self, wish): | 52 | def _count_wish_occurence(self, wish): | ||
53 | """Count the number of times a gift has been wished""" | 53 | """Count the number of times a gift has been wished""" | ||
54 | 54 | ||||
55 | count = 0 | 55 | count = 0 | ||
56 | for key, val in self._wishes.items(): | 56 | for key, val in self._wishes.items(): | ||
57 | if(val == wish): | 57 | if(val == wish): | ||
58 | count += 1 | 58 | count += 1 | ||
59 | return count | 59 | return count | ||
60 | 60 | ||||
61 | @property | 61 | @property | ||
62 | def _get_most_wanted_gift_count(self): | 62 | def _get_most_wanted_gift_count(self): | ||
63 | """Get the number of times the most wanted gift has been wished""" | 63 | """Get the number of times the most wanted gift has been wished""" | ||
64 | 64 | ||||
65 | max_count = 0 | 65 | max_count = 0 | ||
66 | for key, val in self._wishes.items(): | 66 | for key, val in self._wishes.items(): | ||
67 | curr_count = self._count_wish_occurence(val) | 67 | curr_count = self._count_wish_occurence(val) | ||
68 | if curr_count > max_count: | 68 | if curr_count > max_count: | ||
69 | max_count = curr_count | 69 | max_count = curr_count | ||
70 | return max_count | 70 | return max_count | ||
71 | 71 | ||||
72 | @property | 72 | @property | ||
73 | def _get_most_wanted_gift(self): | 73 | def _get_most_wanted_gift(self): | ||
74 | """Get the most wanted gift""" | 74 | """Get the most wanted gift""" | ||
75 | 75 | ||||
76 | most_wanted_gift_count = self._get_most_wanted_gift_count | 76 | most_wanted_gift_count = self._get_most_wanted_gift_count | ||
77 | for key, val in self._wishes.items(): | 77 | for key, val in self._wishes.items(): | ||
78 | if self._count_wish_occurence(val) == most_wanted_gift_count: | 78 | if self._count_wish_occurence(val) == most_wanted_gift_count: | ||
79 | return val | 79 | return val | ||
80 | 80 | ||||
81 | def _clear_xmas(self): | 81 | def _clear_xmas(self): | ||
82 | """Clear the wishes and _naughty_kids""" | 82 | """Clear the wishes and _naughty_kids""" | ||
83 | 83 | ||||
84 | self._wishes.clear() | 84 | self._wishes.clear() | ||
85 | Kid._naughty_kids.clear() | 85 | Kid._naughty_kids.clear() | ||
86 | 86 | ||||
87 | def xmas(self): | 87 | def xmas(self): | ||
88 | Kid._increment_ages() | 88 | Kid._increment_ages() | ||
89 | 89 | ||||
90 | if not self._wishes: | 90 | if not self._wishes: | ||
91 | return | 91 | return | ||
92 | 92 | ||||
93 | most_wanted_gift = self._get_most_wanted_gift | 93 | most_wanted_gift = self._get_most_wanted_gift | ||
94 | for identity, kid in Kid._kids_instances.items(): | 94 | for identity, kid in Kid._kids_instances.items(): | ||
95 | if Kid._kids_ages[identity] <= 5: | 95 | if Kid._kids_ages[identity] <= 5: | ||
96 | if kid in Kid._naughty_kids: | 96 | if kid in Kid._naughty_kids: | ||
t | 97 | kid("coal") | t | 97 | kid('coal') |
98 | else: | 98 | else: | ||
99 | if identity in self._wishes: | 99 | if identity in self._wishes: | ||
100 | wish = self._wishes[identity] | 100 | wish = self._wishes[identity] | ||
101 | else: | 101 | else: | ||
102 | wish = most_wanted_gift | 102 | wish = most_wanted_gift | ||
103 | kid(wish) | 103 | kid(wish) | ||
104 | 104 | ||||
105 | self._clear_xmas() | 105 | self._clear_xmas() | ||
106 | 106 | ||||
107 | 107 | ||||
108 | class Kid(type): | 108 | class Kid(type): | ||
109 | _kids_ages = {} | 109 | _kids_ages = {} | ||
110 | _kids_instances = {} | 110 | _kids_instances = {} | ||
111 | _naughty_kids = set() | 111 | _naughty_kids = set() | ||
112 | 112 | ||||
113 | @classmethod | 113 | @classmethod | ||
114 | def _check_naughty(cls, method): | 114 | def _check_naughty(cls, method): | ||
115 | def wrapper(self, *args, **kwargs): | 115 | def wrapper(self, *args, **kwargs): | ||
116 | """Add the instance to _naughty_kids if an exception is raised in method""" | 116 | """Add the instance to _naughty_kids if an exception is raised in method""" | ||
117 | 117 | ||||
118 | try: | 118 | try: | ||
119 | return method(self, *args, **kwargs) | 119 | return method(self, *args, **kwargs) | ||
120 | except Exception: | 120 | except Exception: | ||
121 | cls._naughty_kids.add(self) | 121 | cls._naughty_kids.add(self) | ||
122 | raise | 122 | raise | ||
123 | return wrapper | 123 | return wrapper | ||
124 | 124 | ||||
125 | def __new__(cls, name, bases, dct): | 125 | def __new__(cls, name, bases, dct): | ||
126 | if '__call__' not in dct: | 126 | if '__call__' not in dct: | ||
127 | raise NotImplementedError('Sorry, but the instance of the class should be callable (dont get angry, please) :)') | 127 | raise NotImplementedError('Sorry, but the instance of the class should be callable (dont get angry, please) :)') | ||
128 | 128 | ||||
129 | for attribute_name, attribute_val in dct.items(): | 129 | for attribute_name, attribute_val in dct.items(): | ||
130 | if hasattr(attribute_val, '__call__'): | 130 | if hasattr(attribute_val, '__call__'): | ||
131 | if not attribute_name.startswith('_'): | 131 | if not attribute_name.startswith('_'): | ||
132 | dct[attribute_name] = cls._check_naughty(attribute_val) | 132 | dct[attribute_name] = cls._check_naughty(attribute_val) | ||
133 | 133 | ||||
134 | return super().__new__(cls, name, bases, dct) | 134 | return super().__new__(cls, name, bases, dct) | ||
135 | 135 | ||||
136 | def __call__(cls, *args, **kwargs): | 136 | def __call__(cls, *args, **kwargs): | ||
137 | new_kid = super().__call__(*args, **kwargs) | 137 | new_kid = super().__call__(*args, **kwargs) | ||
138 | identity = id(new_kid) | 138 | identity = id(new_kid) | ||
139 | cls._kids_ages[identity] = 0 | 139 | cls._kids_ages[identity] = 0 | ||
140 | cls._kids_instances[identity] = new_kid | 140 | cls._kids_instances[identity] = new_kid | ||
141 | return new_kid | 141 | return new_kid | ||
142 | 142 | ||||
143 | @classmethod | 143 | @classmethod | ||
144 | def _increment_ages(cls): | 144 | def _increment_ages(cls): | ||
145 | """Increment the age of each kid by one year""" | 145 | """Increment the age of each kid by one year""" | ||
146 | 146 | ||||
147 | for identity, age in cls._kids_ages.items(): | 147 | for identity, age in cls._kids_ages.items(): | ||
148 | cls._kids_ages[identity] += 1 | 148 | cls._kids_ages[identity] += 1 |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | import re | f | 1 | import re |
t | 2 | from unittest.mock import Mock | t | ||
3 | 2 | ||||
4 | 3 | ||||
5 | class Singleton(type): | 4 | class Singleton(type): | ||
6 | _instances = {} | 5 | _instances = {} | ||
7 | 6 | ||||
8 | def __call__(cls, *args, **kwargs): | 7 | def __call__(cls, *args, **kwargs): | ||
9 | if cls not in cls._instances: | 8 | if cls not in cls._instances: | ||
10 | cls._instances[cls] = super().__call__(*args, **kwargs) | 9 | cls._instances[cls] = super().__call__(*args, **kwargs) | ||
11 | return cls._instances[cls] | 10 | return cls._instances[cls] | ||
12 | 11 | ||||
13 | 12 | ||||
14 | class Santa(metaclass=Singleton): | 13 | class Santa(metaclass=Singleton): | ||
15 | def __init__(self): | 14 | def __init__(self): | ||
16 | self._wishes = {} | 15 | self._wishes = {} | ||
17 | 16 | ||||
18 | def _get_wish(self, text): | 17 | def _get_wish(self, text): | ||
19 | """Get the wish from the letter/call""" | 18 | """Get the wish from the letter/call""" | ||
20 | 19 | ||||
21 | pattern = r'[\"\']([A-Za-z0-9 ]+)[\"\']' | 20 | pattern = r'[\"\']([A-Za-z0-9 ]+)[\"\']' | ||
22 | wish = re.search(pattern, text) | 21 | wish = re.search(pattern, text) | ||
23 | if wish: | 22 | if wish: | ||
24 | return wish.group(1) | 23 | return wish.group(1) | ||
25 | 24 | ||||
26 | def __call__(self, kid, text): | 25 | def __call__(self, kid, text): | ||
27 | wish = self._get_wish(text) | 26 | wish = self._get_wish(text) | ||
28 | if wish: | 27 | if wish: | ||
29 | self._wishes[id(kid)] = wish | 28 | self._wishes[id(kid)] = wish | ||
30 | 29 | ||||
31 | def _get_signature(self, text): | 30 | def _get_signature(self, text): | ||
32 | """Get the signature of the kid from the letter""" | 31 | """Get the signature of the kid from the letter""" | ||
33 | 32 | ||||
34 | pattern = r'\b\d+\b(?=\s*$)' | 33 | pattern = r'\b\d+\b(?=\s*$)' | ||
35 | signature = re.search(pattern, text) | 34 | signature = re.search(pattern, text) | ||
36 | if signature: | 35 | if signature: | ||
37 | return signature.group().strip() | 36 | return signature.group().strip() | ||
38 | 37 | ||||
39 | def __matmul__(self, text): | 38 | def __matmul__(self, text): | ||
40 | signature = self._get_signature(text) | 39 | signature = self._get_signature(text) | ||
41 | wish = self._get_wish(text) | 40 | wish = self._get_wish(text) | ||
42 | if signature and wish: | 41 | if signature and wish: | ||
43 | self._wishes[int(signature)] = wish | 42 | self._wishes[int(signature)] = wish | ||
44 | 43 | ||||
45 | @property | 44 | @property | ||
46 | def _generator(self): | 45 | def _generator(self): | ||
47 | for key, val in self._wishes.items(): | 46 | for key, val in self._wishes.items(): | ||
48 | yield self._wishes[key] | 47 | yield self._wishes[key] | ||
49 | 48 | ||||
50 | def __iter__(self): | 49 | def __iter__(self): | ||
51 | return self._generator | 50 | return self._generator | ||
52 | 51 | ||||
53 | def _count_wish_occurence(self, wish): | 52 | def _count_wish_occurence(self, wish): | ||
54 | """Count the number of times a gift has been wished""" | 53 | """Count the number of times a gift has been wished""" | ||
55 | 54 | ||||
56 | count = 0 | 55 | count = 0 | ||
57 | for key, val in self._wishes.items(): | 56 | for key, val in self._wishes.items(): | ||
58 | if(val == wish): | 57 | if(val == wish): | ||
59 | count += 1 | 58 | count += 1 | ||
60 | return count | 59 | return count | ||
61 | 60 | ||||
62 | @property | 61 | @property | ||
63 | def _get_most_wanted_gift_count(self): | 62 | def _get_most_wanted_gift_count(self): | ||
64 | """Get the number of times the most wanted gift has been wished""" | 63 | """Get the number of times the most wanted gift has been wished""" | ||
65 | 64 | ||||
66 | max_count = 0 | 65 | max_count = 0 | ||
67 | for key, val in self._wishes.items(): | 66 | for key, val in self._wishes.items(): | ||
68 | curr_count = self._count_wish_occurence(val) | 67 | curr_count = self._count_wish_occurence(val) | ||
69 | if curr_count > max_count: | 68 | if curr_count > max_count: | ||
70 | max_count = curr_count | 69 | max_count = curr_count | ||
71 | return max_count | 70 | return max_count | ||
72 | 71 | ||||
73 | @property | 72 | @property | ||
74 | def _get_most_wanted_gift(self): | 73 | def _get_most_wanted_gift(self): | ||
75 | """Get the most wanted gift""" | 74 | """Get the most wanted gift""" | ||
76 | 75 | ||||
77 | most_wanted_gift_count = self._get_most_wanted_gift_count | 76 | most_wanted_gift_count = self._get_most_wanted_gift_count | ||
78 | for key, val in self._wishes.items(): | 77 | for key, val in self._wishes.items(): | ||
79 | if self._count_wish_occurence(val) == most_wanted_gift_count: | 78 | if self._count_wish_occurence(val) == most_wanted_gift_count: | ||
80 | return val | 79 | return val | ||
81 | 80 | ||||
82 | def _clear_xmas(self): | 81 | def _clear_xmas(self): | ||
83 | """Clear the wishes and _naughty_kids""" | 82 | """Clear the wishes and _naughty_kids""" | ||
84 | 83 | ||||
85 | self._wishes.clear() | 84 | self._wishes.clear() | ||
86 | Kid._naughty_kids.clear() | 85 | Kid._naughty_kids.clear() | ||
87 | 86 | ||||
88 | def xmas(self): | 87 | def xmas(self): | ||
89 | Kid._increment_ages() | 88 | Kid._increment_ages() | ||
90 | 89 | ||||
91 | if not self._wishes: | 90 | if not self._wishes: | ||
92 | return | 91 | return | ||
93 | 92 | ||||
94 | most_wanted_gift = self._get_most_wanted_gift | 93 | most_wanted_gift = self._get_most_wanted_gift | ||
95 | for identity, kid in Kid._kids_instances.items(): | 94 | for identity, kid in Kid._kids_instances.items(): | ||
96 | if Kid._kids_ages[identity] <= 5: | 95 | if Kid._kids_ages[identity] <= 5: | ||
97 | if kid in Kid._naughty_kids: | 96 | if kid in Kid._naughty_kids: | ||
98 | kid("coal") | 97 | kid("coal") | ||
99 | else: | 98 | else: | ||
100 | if identity in self._wishes: | 99 | if identity in self._wishes: | ||
101 | wish = self._wishes[identity] | 100 | wish = self._wishes[identity] | ||
102 | else: | 101 | else: | ||
103 | wish = most_wanted_gift | 102 | wish = most_wanted_gift | ||
104 | kid(wish) | 103 | kid(wish) | ||
105 | 104 | ||||
106 | self._clear_xmas() | 105 | self._clear_xmas() | ||
107 | 106 | ||||
108 | 107 | ||||
109 | class Kid(type): | 108 | class Kid(type): | ||
110 | _kids_ages = {} | 109 | _kids_ages = {} | ||
111 | _kids_instances = {} | 110 | _kids_instances = {} | ||
112 | _naughty_kids = set() | 111 | _naughty_kids = set() | ||
113 | 112 | ||||
114 | @classmethod | 113 | @classmethod | ||
115 | def _check_naughty(cls, method): | 114 | def _check_naughty(cls, method): | ||
116 | def wrapper(self, *args, **kwargs): | 115 | def wrapper(self, *args, **kwargs): | ||
117 | """Add the instance to _naughty_kids if an exception is raised in method""" | 116 | """Add the instance to _naughty_kids if an exception is raised in method""" | ||
118 | 117 | ||||
119 | try: | 118 | try: | ||
120 | return method(self, *args, **kwargs) | 119 | return method(self, *args, **kwargs) | ||
121 | except Exception: | 120 | except Exception: | ||
122 | cls._naughty_kids.add(self) | 121 | cls._naughty_kids.add(self) | ||
123 | raise | 122 | raise | ||
124 | return wrapper | 123 | return wrapper | ||
125 | 124 | ||||
126 | def __new__(cls, name, bases, dct): | 125 | def __new__(cls, name, bases, dct): | ||
127 | if '__call__' not in dct: | 126 | if '__call__' not in dct: | ||
128 | raise NotImplementedError('Sorry, but the instance of the class should be callable (dont get angry, please) :)') | 127 | raise NotImplementedError('Sorry, but the instance of the class should be callable (dont get angry, please) :)') | ||
129 | 128 | ||||
130 | for attribute_name, attribute_val in dct.items(): | 129 | for attribute_name, attribute_val in dct.items(): | ||
131 | if hasattr(attribute_val, '__call__'): | 130 | if hasattr(attribute_val, '__call__'): | ||
132 | if not attribute_name.startswith('_'): | 131 | if not attribute_name.startswith('_'): | ||
133 | dct[attribute_name] = cls._check_naughty(attribute_val) | 132 | dct[attribute_name] = cls._check_naughty(attribute_val) | ||
134 | 133 | ||||
135 | return super().__new__(cls, name, bases, dct) | 134 | return super().__new__(cls, name, bases, dct) | ||
136 | 135 | ||||
137 | def __call__(cls, *args, **kwargs): | 136 | def __call__(cls, *args, **kwargs): | ||
138 | new_kid = super().__call__(*args, **kwargs) | 137 | new_kid = super().__call__(*args, **kwargs) | ||
139 | identity = id(new_kid) | 138 | identity = id(new_kid) | ||
140 | cls._kids_ages[identity] = 0 | 139 | cls._kids_ages[identity] = 0 | ||
141 | cls._kids_instances[identity] = new_kid | 140 | cls._kids_instances[identity] = new_kid | ||
142 | return new_kid | 141 | return new_kid | ||
143 | 142 | ||||
144 | @classmethod | 143 | @classmethod | ||
145 | def _increment_ages(cls): | 144 | def _increment_ages(cls): | ||
146 | """Increment the age of each kid by one year""" | 145 | """Increment the age of each kid by one year""" | ||
147 | 146 | ||||
148 | for identity, age in cls._kids_ages.items(): | 147 | for identity, age in cls._kids_ages.items(): | ||
149 | cls._kids_ages[identity] += 1 | 148 | cls._kids_ages[identity] += 1 |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|