Домашни > Подаръци ще има за всички от сърце > Решения > Решението на Стивън Александров

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

8 точки общо

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

  1import re
  2import random
  3# Начална форма на домашното, не е готово, едно от нещата не знам баш как да го направя, ако се сетя ще го добавя
  4# качвам това евентуално ако го прегледате до към 12ч на четвъртък, да дадете някаква обратна връзка
  5id_to_kid = {} # ще пазя id на дете като ключ и инстанцията като стойност, за да не се налага иначе да правя некви кастове и такива c++ неща

Мисля, че е по-добре това да живее в Kid класа.

6DEFAULT_PRESENT = "coal" 7

Оставяй по два празни реда между код на top level.

8def default_init_method(self, *args, **kwargs): # За да стане трика с id_to_kid dict-a, ще ми трябва по някъв начин от обектите от новосъздадените класове да го пълня

Струва ми се излишно да имаш функция, която прави нещо на един ред, която използваш само на едно място.

9 id_to_kid[id(self)] = self 10 11class Kid(type): 12 13 def __new__(cls, name, bases, dictionary_of_attributes): 14 if "__call__" not in dictionary_of_attributes: 15 raise NotImplementedError("леко баце") 16 dictionary_of_attributes["__init__"] = default_init_method

А ако класът, който получиш вече има __init__ и то го презапишеш?
По-добре добави новият обект експлицитно тук. Това, което текущият метод връща, можеш да вземеш и използваш преди да го върнеш.

17 # добавяме една променлива age, да ни казва на колко години е детето 18 dictionary_of_attributes["age"] = 0 19 return super().__new__(cls, name, bases, dictionary_of_attributes) 20 21 22 23class Santa: 24 _instance = None 25 # причината да има както list_of_presents, така и wishlist, ще разберете отдолу при iter() 26 _list_of_presents = [] 27 _wishlist = {} 28 29 def __new__(cls): 30 # Ако това е първото извикване на new, създаваме обекта и го пращаме в _instance 31 # При второ и всяко следващо, директно връщаме вeче създадения обект, за да постигнем singleton 32 if cls._instance is None: 33 cls._instance = super(Santa, cls).__new__(cls) 34 return cls._instance 35 36 def _find_index_in_list(self, present):

Имаш index метод върху списъка, който върши тази работа.

37 for i in range(len(Santa._list_of_presents)): 38 if Santa._list_of_presents[i] == present: 39 return i 40 41 def __call__(self, kid, wish): 42 # regex (smile face) 43 try: 44 wanted_present = re.search(r"\'[a-zA-Z0-9\s]*\'|\"[a-zA-Z0-9\s]*\"", wish).group() 45 # слагаме го без кавичките, затова ще го slice-ваме

Можеш да използваш групи, за да не се налага да го правиш, но и така е ок.

46 wanted_present = wanted_present[1:len(wanted_present)-1] 47 if id(kid) in Santa._wishlist: 48 # по въпроса на колегата дали редът се променя ако Дете1 иска чорап, Дете2 - раница, и след това Дете1 - игра

Както ще видиш по-долу, можеш и без този лист и ще е по-лесно.

49 # ако детето вече е искало нещо, то новото не трябва да го бутаме отзад, ами трябва да го сложим на правилното място 50 index = self._find_index_in_list(Santa._wishlist[id(kid)]) 51 Santa._list_of_presents[index] = wanted_present 52 else: 53 Santa._list_of_presents.append(wanted_present) 54 # id на дете -> подарък, който иска 55 Santa._wishlist[id(kid)] = wanted_present 56 except: 57 # Ако Писмото е невалидно 58 pass

По принцип except pass е антипатърн и е редно да се избягва. По-добре остави грешката да се вдигне, за да е ясно на изикващия, че нещо се е прецакало.

59 60 # operator @ ?!?!?! 61 def __matmul__(self, letter):

Доста сходно с горното. Можеш да се опиташ да ги обединиш.

62 # regex (smile face) 63 try: 64 wanted_present = re.search(r"\'[a-zA-Z0-9\s]*\'|\"[a-zA-Z0-9\s]*\"", letter).group() 65 kid_sign = re.search(r"(\n)\s*\d+\s*", letter).group() 66 # Ще хване и whitespace, затова трябва да ги махнем 67 kid_sign = int(kid_sign.strip()) 68 # слагаме го без кавичките, затова ще го slice-ваме 69 wanted_present = wanted_present[1:len(wanted_present)-1] 70 if kid_sign in Santa._wishlist: 71 # подобни обяснения като отгоре 72 index = self._find_index_in_list(Santa._wishlist[kid_sign]) 73 Santa._list_of_presents[index] = wanted_present 74 else: 75 Santa._list_of_presents.append(wanted_present) 76 # id на дете -> подарък, който иска 77 Santa._wishlist[kid_sign] = wanted_present 78 except: 79 # Ако Писмото е невалидно 80 pass 81 82 def __iter__(self): 83 # има отделно list_of_presents и wishlist, въпреки че съхраняват еднакви неща (почти)

От Python 3.7 насам речниците са подредени. Ако искаш да си абсолютно сигурен, че кодът ти ще е ок дори на по-сотара версия, можеш да използваш OrderedDict

84 # причината е, че редът на листа е гарантиран, докато за dict-a не съм сигурен дали е рандом, или сортиран, или каквото и да е 85 # зависи от имплементацията на dict отдолу, затова list-a е по-сигурния за мен вариант 86 return iter(Santa._list_of_presents) 87 88 def _find_most_popular_present(self): 89 if len(Santa._list_of_presents) == 0: 90 return None 91 dict_of_present = {} 92 for item in Santa._list_of_presents:

max(some_list, key=some_list.count)

93 if item not in dict_of_present: 94 dict_of_present[item] = 1 95 else: 96 dict_of_present[item] += 1 97 # предполагам, че очаквате да използвам random, щом в условието пише ,,На случаен принцип''

Целта на това "на случаен принцип" е просто да отговорим на евентуалния въпрос какво да правите при повече от един елемент с максимален брой срещания.
Реално погледнато, просто можеш да върнеш един от тях. Примерно, ако имаш сортиран списък, взимаш първият елемент и толков. Това е пак вид "случаен принцип", но не имплементираш нищо свързано с random.

98 # затова и трябва малко setup за random-a 99 # или иначе казано търся си оправдание да напиша най-лошото търсене в историята 100 max_app = 0 101 for app in dict_of_present.values(): 102 if app > max_app: 103 max_app = app 104 list_of_popular_presents = [] 105 for item in dict_of_present.keys(): 106 if dict_of_present[item] == max_app: 107 list_of_popular_presents.append(item) 108 random_position = random.randint(0, len(list_of_popular_presents) - 1) 109 return list_of_popular_presents[random_position] 110 111 def xmas(self): 112 for kid_id in id_to_kid.keys(): 113 if id_to_kid[kid_id].age >= 5: # по скоро е броя на изминалите коледи, а не е възраст

Добре е тази петица да е константа.

114 continue 115 else: 116 # не знам как да направя проверка дали дете е хвърлило exception :( 117 if kid_id in Santa._wishlist: 118 id_to_kid[kid_id].__call__(Santa._wishlist[kid_id]) 119 else: 120 most_popular_present = self._find_most_popular_present() 121 if most_popular_present is not None: 122 id_to_kid[kid_id].__call__(most_popular_present) 123 id_to_kid[kid_id].age += 1 124 Santa._list_of_presents = [] 125 Santa._wishlist = {}

.............FEE..E.
======================================================================
ERROR: test_xmass_no_wishes (test.TestSanta.test_xmass_no_wishes)
Test a Christmas with no wishes.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 151, in test_xmass_no_wishes
self.assertEqual(kid1.SECRET_PRESENT, None)
^^^^^^^^^^^^^^^^^^^
AttributeError: 'KidClass1' object has no attribute 'SECRET_PRESENT'

======================================================================
ERROR: test_xmass_no_wishes_but_naughty_kids (test.TestSanta.test_xmass_no_wishes_but_naughty_kids)
Test a Christmas with no wishes, but naughty kids present.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 163, in test_xmass_no_wishes_but_naughty_kids
self.assertEqual(kid1.SECRET_PRESENT, None)
^^^^^^^^^^^^^^^^^^^
AttributeError: 'KidClass1' object has no attribute 'SECRET_PRESENT'

======================================================================
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 213, in test_xmass_years_5_and_over
self.assertEqual(kid1.SECRET_PRESENT, None)
^^^^^^^^^^^^^^^^^^^
AttributeError: 'KidClass1' object has no attribute 'SECRET_PRESENT'

======================================================================
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 227, in test_xmass_naughty
self.assertEqual(kid1.SECRET_PRESENT, 'coal')
AssertionError: 'sirenie' != 'coal'
- sirenie
+ coal

----------------------------------------------------------------------
Ran 20 tests in 0.026s

FAILED (failures=1, errors=3)

Дискусия
История
Това решение има само една версия.