Домашни > Подаръци ще има за всички от сърце > Решения > Решението на Марина Господинова

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

8 точки общо

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

  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` не прави нищо.
История
Това решение има само една версия.