1from collections import Counter
2import re
3
4
5class Santa(dict):
6 _iter_flag = False
7
8 def __new__(cls):
9 if not hasattr(cls, 'instance'):
10 cls.instance = super(Santa, cls).__new__(cls)
11 return cls.instance
12
13 def __iter__(self):
14 if(Santa._iter_flag):
15 return iter(self.keys())
16 return iter(self.values())
17
18 def items_iter(self):
19 for key, value in self.items():
20 yield key, value
21
22 def __call__(self, kid, message):
23 wish = re.search(r'("|\')([\w\s]+)\1', message).group(2)
24 Santa._iter_flag = True
25 self.instance[kid] = wish
26 Santa._iter_flag = False
27
28 def __matmul__(self, letter):
29 wish = re.search(r'("|\')([\w\s]+)\1', letter).group(2)
30 signature = re.search(r'\b(\d+)\b', letter).group()
31 Santa._iter_flag = True
32 for kid in self.keys():
33 hash = id(kid)
34 if hash == int(signature):
35 self.instance[kid] = wish
36 Santa._iter_flag = False
37
38 def find_what_kids_want(self):
39 all_gifts = [value for value in self.values() if value]
40 if not all_gifts:
41 return None
42 wanted_gift = Counter(all_gifts).most_common(1)[0]
43 return wanted_gift[0]
44
45 def xmas(self):
46 Santa._iter_flag = True
47 best_gift = self.find_what_kids_want()
48 for kid, gift in self.instance.items():
49 if not best_gift:
50 kid.age += 1
51 continue
52 if(kid.age >= 5):
53 continue
54 elif kid.is_naughty:
55 kid('coal')
56 self.instance[kid] = None
57 kid.is_naughty = False
58 continue
59 elif not gift:
60 kid(best_gift)
61 else:
62 kid(gift)
63 self.instance[kid] = None
64 Santa._iter_flag = False
65
66
67class Kid(type):
68 @staticmethod
69 def track_naughtiness(method):
70 def wrapped(self, *args, **kwargs):
71 try:
72 return method(self, *args, **kwargs)
73 except Exception:
74 self.is_naughty = True
75 return wrapped
76
77 @staticmethod
78 def notify_santa(kid):
79 """Tell Santa that a child was born"""
80 santa = Santa()
81 Santa._iter_flag = True
82 santa[kid] = None
83 Santa._iter_flag = False
84
85 @classmethod
86 def mark_naughty_kids(cls, dct):
87 for attr_name, attr_value in dct.items():
88 if callable(attr_value) and not attr_name.startswith('_'):
89 dct[attr_name] = cls.track_naughtiness(attr_value)
90
91 def __new__(cls, name, bases, dct):
92 if '__call__' not in dct:
93 raise NotImplementedError(
94 "Дете, което не идва дори когато го викаш за подарък, "
95 "не пренебрегва подаръка – то пренебрегва доверието и уважението, "
96 "които гласът ти би трябвало да носи."
97 )
98 updated_dct = dict(dct)
99 cls.mark_naughty_kids(updated_dct)
100 updated_dct["age"] = 0
101 updated_dct["is_naughty"] = False
102
103 original_call = updated_dct["__call__"]
104
105 def wrapped_call(self, present):
106 self.age += 1
107 return original_call(self, present)
108
109 def __eq__(self, other):
110 return id(self) == id(other)
111
112 def __hash__(self):
113 return id(self)
114
115 updated_dct["__call__"] = wrapped_call
116 updated_dct["__eq__"] = __eq__
117 updated_dct["__hash__"] = __hash__
118
119 return super().__new__(cls, name, bases, updated_dct)
120
121 def __call__(cls, *args, **kwargs):
122 instance = super().__call__(*args, **kwargs)
123 cls.notify_santa(instance)
124 return instance
......FFF....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: ['кавички', 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 '] != ['toy4', 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 ']
First differing element 0:
'кавички'
'toy4'
- ['кавички', 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 ']
? ^^^^^^^
+ ['toy4', 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 ']
? ^^^^
======================================================================
FAIL: 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 260, in test_santa_gift_order
self.assertEqual(list(self.santa), ["toy2v2", "toy3", "toy1"])
AssertionError: Lists differ: ['toy1', 'toy2v2', 'toy3'] != ['toy2v2', 'toy3', 'toy1']
First differing element 0:
'toy1'
'toy2v2'
- ['toy1', 'toy2v2', 'toy3']
+ ['toy2v2', 'toy3', 'toy1']
======================================================================
FAIL: 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 119, in test_signature_matching
self.assertEqual(kid2.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
----------------------------------------------------------------------
Ran 20 tests in 0.022s
FAILED (failures=4)
Марина Господинова
20.12.2024 14:27Да, и аз проверих кода си отново, явно в някакъв момент нещо друго по логиката не е работело както трябва и съм се заблудила, че проблема е оттук и трябва да правя "двойствено" поведение. Благодаря за отговора и весели празници!
|
Георги Кунчев
20.12.2024 11:38Да уточня дискусията от вчера. Написах следния безумен код:
```
class Test(dict):
def __iter__(self):
return iter(self.values())
test = Test()
test = {'1': 1, '2': 2}
for x in test:
print(type(x), x)
```
Бях изумен, че в този вариант `__iter__` не работи и итераторът все пак цикли по ключовете, а не по стойностите.
Е, днес се сетих защо. `test = {'1': 1, '2': 2}` реално дефинира обикновен речник, така че класът ми няма никакво значение.
Ако вместо този ред, сетна стойностите адекватно, всичко е ок:
```
class Test(dict):
def __iter__(self):
return iter(self.values())
test = Test()
test['1'] = 1
test['2'] = 2
# алтернативно, може и направо така: test = Test({'1': 1, '2': 2})
for x in test:
print(type(x), x)
```
Та, изводът е, че поведението е напълно очаквано. Имплементацията на `__iter__` работи правилно. Флагът ти `_iter_flag` не прави нищо.
|
19.12.2024 15:16
19.12.2024 15:23
19.12.2024 15:15
19.12.2024 15:19
19.12.2024 15:18
19.12.2024 15:20
19.12.2024 15:21