Тъй като все още не сте добили достатъчно познания за света на Монти Пайтън, искаме да ви обогатим със следния откъс от техен филм:
Целта на домашното е да напишете функция, която симулира рицарите, които казват "Ni!".
Както става ясно от видеото, рицарите винаги отговарят с "Ni!", освен ако не им бъде предоставено "shrubbery" (храсталак) и то само при условие, че храсталакът е "one that looks nice" (такъв, който изглежда хубаво) и "not too expensive" (не прекалено скъп). Е, не винаги, но ние ще го опростим.
Целта ви е да напишете функция, която оценява получения си вход и определя дали е получила храсталак, който изглежда хубаво и не е прекалено скъп.
Напишете функцията function_that_says_ni
, която приема произволен брой позиционни и/или именувани параметри.
Стойностите на тези параметри могат да бъдат от произволен тип, но тези, които касаят поведението на функцията, са само аргументите от тип dict
(речник). Всички останали могат да бъдат пренебрегнати.
Ако аргумент на функцията (било то позиционен или именуван) е от тип dict
, то той е потенциално "храст".
Речник, който описва "храст", трябва да отговаря на следното условие:
Речникът има ключ от тип str
със стойност name
, зад който ключ има стойност от тип str
и някоя от следните стойности "храст", "shrub", "bush". Може и в комбинация от малки/главни букви.
Речник, който описва "храст", може да съдържа и друг ключ от тип str
със стойност cost
, зад който ключ има стойност от тип int
или float
, показващ цената на дадения храст, но такъв ключ може и да не се съдържа в речника.
Речникът може да има и други ключове, но всичко извън name
и cost
не ни интересува.
Например:
{"name": "чегарак", "cost": 1.00} # Не е "храст", защото "чегарак" не фигурира в списъка по-горе
{"name": "храст", "cost": 2.00} # Това е "храст"
{"name": "shrub", "cost": 3.00} # Това е "храст"
{"name": "bush"} # Това е "храст". Цената не е задължителна.
Целта ви е да оцените всички "храст"-и, които вашата функция приеме като вход, и да прецените дали сте удовлетворени, или не.
В случай, че не сте получили храсталак (комбинация от "храсти"-и), който изглежда хубаво и не е прекалено скъп, функцията ви трябва да връща str
със стойност "Ni!".
В противен случай трябва да върнете str
, който съответства на цената на храсталака, който сте получили, във формата "1.23лв" (винаги закръглен до два символа след десетичната запетая и включвайки "лв" накрая.
Цената на храсталак се определя като сума от всички "храст"-и, които функцията ви е получила като вход.
Един храсталак е прекалено скъп, ако цената му е повече от 42.00лв.
Един храсталак изглежда хубав, когато броят от уникалните букви, които са използвани за изписване на имената на всички именувани аргументи на функцията, които представляват "храст"-и, е кратен на целочислената част от цената му.
*Кратно се нарича цяло число, което се дели на друго число без остатък.
Например:
Ако цената на храсталака, който сте получили, е "2.80лв", то той е по-евтин от 42.00лв, но за да удовлетворите функцията, трябва да се уверите и че храсталакът е хубав.
Хубав храсталак в този случай би бил само такъв, че броят от уникалните буквите, използвани в имена на именувани аргументи, които представляват "храст"-и, е кратен на 2 (цялата част от 2.80).
function_that_says_ni(ab={"name": "храст", "cost": 1.80}, bc={"name": "храст", "cost": 1})
# Броят уникалните букви, използвани за дефиниране на имената на именувани аргументи, е 3 ("a", "b" и "c").
# 3 не е кратно на 2 (цялата част от сумата), така че това не е хубав храсталак.
cost
от тип float
, може да има стойност най-много до втора цифра след десетичната запетая. Няма да тестваме с по-висока точност. cost
, се счита за безплатен, т.е. има цена 0. cost
, може да има само стойности int
и float
зад този ключ. Няма да тестваме с невалидни цени зад запазеното име за това. function_that_says_ni({"name": "храст", "cost": 120})
> "Ni!"
# Независимост от всичко останало, очевидно този храсталак е прекалено скъп
function_that_says_ni({"name": "храст", "cost": 1})
> "1.00лв"
# Цената е под максимума, а общият брой букви, използвани като именувани аргументи за дефиниране на "храст"-и, е 0, което е кратно на 1.
function_that_says_ni(aabcc={"name": "bush", "cost": 3.20})
> "3.20лв"
# Цената е под максимума. Общият брой уникални букви, използвани като именувани аргументи за дефиниране на "храст"-и, е 3 ("a", "b", "c").
# Целочислената част на цената също е 3. Кратността е изпълнена, т.е. храсталакът е ок и връщаме цената.
1import unittest
2
3import solution
4
5
6class TestSanity(unittest.TestCase):
7 """Check if the function is present."""
8
9 def test_function(self):
10 self.assertIn('function_that_says_ni', dir(solution), 'Убеди се, че функцията "function_that_says_ni" е налична с точно това име.')
11 self.assertTrue(callable(solution.function_that_says_ni), 'Убеди се, че "function_that_says_ni" е функция.')
12
13
14if __name__ == '__main__':
15 unittest.main()
1import unittest
2
3from solution import *
4
5
6class TestNi(unittest.TestCase):
7 """Test all requirements related to the function that says 'Ni!'."""
8
9 NI = 'Ni!'
10
11 def test_empty(self):
12 """Test with empty input."""
13 self.assertEqual(function_that_says_ni(), self.NI)
14
15 def test_single_with_no_named_args(self):
16 """Test with a single shrub that is passed as positional argument."""
17 self.assertEqual(function_that_says_ni({'name': 'shrub', 'cost': 3.12}), '3.12лв')
18
19 def test_all_possible_shrub_strings(self):
20 """Test with all possible strings that define a shrub."""
21 self.assertEqual(function_that_says_ni({'name': 'shrub', 'cost': 1}), '1.00лв')
22 self.assertEqual(function_that_says_ni({'name': 'bush', 'cost': 1}), '1.00лв')
23 self.assertEqual(function_that_says_ni({'name': 'храст', 'cost': 1}), '1.00лв')
24 self.assertEqual(function_that_says_ni({'name': 'SHrub', 'cost': 1}), '1.00лв')
25 self.assertEqual(function_that_says_ni({'name': 'buSH', 'cost': 1}), '1.00лв')
26 self.assertEqual(function_that_says_ni({'name': 'хрАст', 'cost': 1}), '1.00лв')
27
28 def test_with_no_cost(self):
29 """Test with a shrub without defined cost."""
30 self.assertEqual(function_that_says_ni({'name': 'shrub'}), self.NI)
31
32 def test_multiple_shrubs_sumс(self):
33 """Test with a multiple shrubs and cornercase costs."""
34 self.assertEqual(function_that_says_ni({'name': 'shrub', 'cost': 20.00},
35 {'name': 'shrub', 'cost': 22}), '42.00лв')
36 self.assertEqual(function_that_says_ni({'name': 'shrub', 'cost': 19.99},
37 {'name': 'shrub', 'cost': 22}), '41.99лв')
38 self.assertEqual(function_that_says_ni({'name': 'shrub', 'cost': 20.01},
39 {'name': 'shrub', 'cost': 22}), self.NI)
40
41 def test_cost_whole_part_zero(self):
42 """Test with a total cost part equal to zero."""
43 self.assertEqual(function_that_says_ni({'name': 'shrub', 'cost': 0.1},
44 {'name': 'храст', 'cost': 0.2}), self.NI)
45
46 def test_named_arguments(self):
47 """Test with named arguments."""
48 # Case with whole-part cost exactly
49 # devided by number of unique chars = 7
50 self.assertEqual(function_that_says_ni(_abcde={'name': 'shrub', 'cost': 2.82},
51 _abcf={'name': 'bush', 'cost': 4.51}), '7.33лв')
52 # Case with whole-part cost exactly
53 # devided by number of ALL chars (3),
54 # but not by number of unique chars (2)
55 self.assertEqual(function_that_says_ni(a={'name': 'shrub', 'cost': 1},
56 ab={'name': 'bush', 'cost': 2}), self.NI)
57
58 def test_combination_of_arguments(self):
59 """Test with combination of named and positional arguments."""
60 self.assertEqual(function_that_says_ni({'name': 'bush', 'cost': 1},
61 {'name': 'храст', 'cost': 1},
62 a={'name': 'shrub', 'cost': 0},
63 ab={'name': 'bush', 'cost': 0}), '2.00лв')
64
65 def test_invalid_strings(self):
66 """Test with invalid strings that might be misinterpreted."""
67 self.assertEqual(function_that_says_ni({'no_name': 'bush', 'cost': 1}), self.NI)
68 self.assertEqual(function_that_says_ni({'name': 'not a shrub', 'cost': 1}), self.NI)
69 self.assertEqual(function_that_says_ni({'name': 'shrub', ' cost': 1}), self.NI) # Space before cost
70
71
72 def test_other_than_dicts(self):
73 """Test with inputs other than dicts."""
74 self.assertEqual(function_that_says_ni(1, 3.14, ['some_list'], some_arg={1, 2, 3}), self.NI)
75
76
77if __name__ == '__main__':
78 unittest.main()
![]()
Георги Кунчев
22.10.2024 21:10За всички колеги, на които съм писал, че вместо да търсят с |
![]()
Даниел Стефанов
21.10.2024 12:33Ето още тестове: https://pastebin.com/QA1s4nVV Само трябва да си оправите import-a |
|
![]()
Георги Кунчев
18.10.2024 21:44@Василена_Станойска, права си. При така зададеното условие, сума по-голяма от 27 би връщала винаги "Ni!". |
![]()
Василена Станойска
18.10.2024 21:33-> Символът В такъв случай обаче, ако считаме, че името на именуваните аргументи може да ни бъде само от букви, "" и от "_", то в най-добрият случай ние можем да имаме 26 + 1 уникални символа, което после като проверяваме дали това число е кратно на общата сума, то ако сумата ни е по-голяма от 27, то ние винаги ще имаме резултат, че храстът не е хубав и така ограничението за максималната цена не трябва ли да бъде просто 27, вместо 42? Или просто това е поведението, което търсим? |
![]()
Георги Кунчев
18.10.2024 20:59Символът |
![]()
Георги Кунчев
18.10.2024 20:57"Ако се подаде dict който е невалиден храст това означава ли че целият храсталак е невалиден или просто се игнорира" "ако се игнорират в такъв случай трябва ли при позиционните аргументи да се броят само ключовете които са храсти" |
![]()
Василена Станойска
18.10.2024 16:36Здравейте, имам въпрос свързан с предпоследната точка от "Уговорките": когато имаме "_" в името на именованата променлива и след това броим уникалните символи от всички имена на именованите променливи, то този символ броим ли го като уникален, или за всяко негово срещане той си се счита като отделна буква и взимаме предвид накрая и броя на всички негови срещания? |
![]()
Павел Петков
18.10.2024 15:26Ако се подаде dict който е невалиден храст това означава ли че целият храсталак е невалиден или просто се игнорира и ако се игнорират в такъв случай трябва ли при позиционните аргументи да се броят само ключовете които са храсти |
![]()
Илиан Запрянов
18.10.2024 14:11Примерни тестове за Домашно 2 https://docs.google.com/document/d/1XpVwY-X-NKEvOoYVRD_3qR06xLbnZm8v9ahs0i7L29Y/edit?usp=sharing |