В настоящата глава ще се запознаем с функциите и ще научим какво представляват те, както и кои са базовите концепции при работа с тях. Ще научим защо е добра практика да ги използваме, как да ги дефинираме и извикваме. Ще се запознаем с параметри и връщана стойност от функция, както и как да използваме тази връщана стойност. Накрая на главата, ще разгледаме утвърдените практики при използването на функции.
До момента установихме, че при писане на програма, която решава даден проблем, ни улеснява това, че разделяме задачата на части. Всяка част отговаря за дадено действие и по този начин не само ни е по-лесно да решим задачата, но и значително се подобрява както четимостта на кода, така и проследяването за грешки.
В контекста на програмирането, функция (метод) се нарича именувана група от инструкции, които изпълняват дадена фунционалност. Тази група от инструкции е логически отделена и именувана, така че изпълнението на инструкциите в групата може да бъде стартирано чрез това име в хода на изпълнението на програмата. Стартирането на изпълнението на инструкциите във функцията се нарича извикване на функцията (на английски function call или invoking a function).
Една функция може да бъде извикана толкова пъти, колкото ние преценим, че ни е нужно за решаване на даден проблем. Това ни спестява повторението на един и същи код няколко пъти, което от своя страна намалява възможността да пропуснем грешка при евентуална корекция на въпросния код.
Ще разгледаме два типа функции - "прости" (без параметри) и "сложни" (с параметри).
В обектно-ориентираното програмиране (което не е предмет на тази книга) функциите, които са част от класове, се наричат методи. В някои езици за програмиране функциите се наричат още процедури. |
Простите функции отговарят за изпълнението на дадено действие, което спомага за решаване на определен проблем. Такива действия могат да бъдат например разпечатване на даден низ в конзолата, извършване на някаква проверка, изпълнение на цикъл и други.
Нека разгледаме следния пример за проста функция:
Тази функция има задачата да отпечата заглавие, което представлява поредица от символа -
. Поради тази причина името ѝ е print_header
. Кръглите скоби (
и )
винаги следват името на функцията, независимо как сме я именували. Важно е името на функциите, с които работим, да описва действието, което извършват. По-късно в тази глава ще разгледаме още утвърдени практики за избиране на имена на функциите.
Тялото на функцията съдържа програмния код (инструкциите), което се намира на следващия ред, след двуеточието и е изписано с една табулация навътре (с индентация). Двуеточието винаги следва декларацията ѝ и след него поставяме кода, който решава проблема, описан от името на функцията. Тялото на функцията се изписва по-навътре, обикновено 4 интервала (една табулация), които го обособяват като отделен блок инструкции, прилежащи към функцията.
Изпълнението на тази програма само по себе си няма да отпечата нищо на екрана, тъй като още не сме извикали функцията.
До тук установихме, че функциите спомагат за разделянето на обемна задача на по-малки части, което води до по-лесно решаване на въпросното задание. Това прави програмата ни не само по-добре структурирана и лесно четима, но и по-разбираема.
Чрез функциите избягваме повторението на програмен код. Повтарящият се код е лоша практика, тъй като силно затруднява поддръжката на програмата и води до грешки. Ако дадена част от кода ни присъства в програмата няколко пъти и се наложи да променим нещо, то промените трябва да бъдат направени във всяко едно повторение на въпросния код. Вероятността да пропуснем място, на което трябва да нанесем корекция, е много голяма, което би довело до некоректно поведение на програмата. Това е причината, поради която е добра практика, ако използваме даден фрагмент код повече от веднъж в програмата си, да го дефинираме като отделна функция.
Функциите ни предоставят възможността да използваме даден код няколко пъти. С решаването на все повече и повече задачи ще установите, че използването на вече съществуващи функции спестява много време и усилия.
Дефиниране на функция представлява регистрирането на функцията в програмата, за да бъде разпознавана и да може да бъде използвана в останалата част от нея. Със следващия пример ще разгледаме елементите в дефиницията на една функция:
- def. Ключовата дума
def
в езика за програмиране Python показва, че желаем да дефинираме нова функция. - Име на функцията. Името на функцията е определено от нас и следва ключовата дума
def
, като не забравяме, че то трябва да описва действието, което се изпълнява от инструкциите в тялото ѝ. В примера името еcalculate_square
, което ни указва, че задачата на тази функция е да изчисли квадрата на някое число. - Списък с параметри. Дефинира се между скобите
(
и)
, които изписваме след името на функцията. Тук изброяваме поредицата от параметри, които функцията ще използва. Може да присъства само един параметър, няколко такива или да е празен списък. Ако няма параметри, то записваме само скобите()
. В конкретния пример декларираме един параметърnum
. - Двуеточие. След затварящата скоба слагаме двучеточие
:
, което оказва, че започва тялото на функцията. - Имплементация (тяло). В тялото на функцията описваме алгоритъма (инструкциите), по който тя решава даден проблем, т.е. тялото съдържа кода, който реализира логиката на функцията. В показания пример изчисляваме квадрата на дадено число, а именно
num * num
. Тялото се записва на нов ред с индентация.
При дефиниране на функции е важно да спазваме тази конкретна последователност на елементите.
Когато дефинираме дадена променлива в тялото на една функция, я наричаме локална променлива за функцията. Областта, в която съществува и може да бъде използвана тази променлива, започва от реда, на който сме я дефинирали и стига до последната инструкция от блока на тялото (която се намира по-навътре). Тази област се нарича област на видимост на променливата (variable scope).
Извикването на функция представлява стартирането на изпълнението на кода, който се намира в тялото на функцията. Това става като изпишем името на функцията, последвано от кръглите скоби ()
. Ако функцията ни изисква входни данни (параметри), то те се подават в скобите ()
, като последователността на подадените параметри трябва да съвпада с последователността на параметрите при дефинирането на функцията. Ето един пример:
Дадена функция може да бъде извикана от няколко места в нашата програма и повече от един път. Важно е да знаем, че в езика Python, ако една функция е дефинирана някъде в програмата, то тя може да бъде извиквана само след самата ѝ дефиниция.
Тъй като извикването на функция е инструкция сама по себе си, то можем безпроблемно от тялото на една функция да извикаме друга функция:
Съществува вариант функцията да бъде извикана от собственото си тяло. Това се нарича рекурсия и можете да намерите повече информация за нея в Wikipedia или да потърсите сами в Интернет.
Да се напише функция, който печата празна касова бележка. Функцията трябва да извиква други три функции: една за принтиране на заглавието, една за основната част на бележката и една за долната част.
Част от касовата бележка | Текст |
---|---|
Горна част | CASH RECEIPT ------------------------------ |
Средна част | Charged to____________________ Received by___________________ |
Долна част | ------------------------------ (c) SoftUni |
Вход | Изход |
---|---|
(няма) | CASH RECEIPT ------------------------------ Charged to____________________ Received by___________________ ------------------------------ (c) SoftUni |
Първата ни стъпка е да създадем функция за принтиране на заглавната част от касовата бележка (header). Нека ѝ дадем смислено име, което описва кратко и ясно задачата ѝ, например print_receipt_header
. В тялото ѝ ще напишем кода от примера по-долу:
Съвсем аналогично ще създадем още две функции за разпечатване на средната част на бележката (body) print_receipt_body
и за разпечатване на долната част на бележката (footer) print_receipt_footer
.
След това ще създадем и още една функция, която ще извиква трите функции, които написахме до момента една след друга. Накрая ще извикаме функцията print_receipt
от нашата програма:
Програмата с общо четири функции, които се извикват една от друга, е готова и можем да я изпълним и тестваме, след което да я пратим за проверка в Judge системата: https://judge.softuni.org/Contests/Practice/Index/1063#0.
Много често в практиката, за да бъде решен даден проблем, функцията, с чиято помощ постигаме това, се нуждае от допълнителна информация, която зависи от задачата ѝ. Именно тази информация представляват параметрите на функцията и нейното поведение зависи от тях.
Както отбелязахме по-горе, параметрите освен нула на брой, могат също така да са един или няколко. При декларацията им ги разделяме със запетая. Те могат да бъдат от различен тип данни (число, низ и т.н.), а по-долу е показан пример как точно те биват използвани в тялото на функцията.
Ето една примерна дефиниция на функция и списъка ѝ с параметри:
В този пример имаме два параметъра, съответно с имената start
и end
. След дефиницията на функцията, можем да я използваме в програмата - извикваме функцията като ѝ предаваме конкретни стойности за параметрите:
С това извикване на функцията, тялото ѝ ще бъде изпълнено като за параметъра start
ще бъде използвана стойността 5
, а за параметъра end
- стойността 10
.
При декларирането на параметри, можем да използваме различни типове данни като всеки един параметър трябва да има име (което да е смислено). Важно е да отбележим, че при извикване на функцията, трябва да подаваме стойности за параметрите в реда, в който са декларирани.
Нека разгледаме друга примерна дефиниция на функция, която има няколко параметъра от различен тип:
Да се създаде функция, която печата дали подаденото и цяло число е положително, отрицателно или нула.
Вход | Изход |
---|---|
2 | The number 2 is positive. |
-5 | The number -5 is negative. |
0 | The number 0 is zero. |
Първата ни стъпка е създаването на функция и даването ѝ на описателно име, например print_sign
. Тази функция ще има само един параметър - числото, чийто знак искаме да проверим:
Следващата ни стъпка е да имплементрираме логиката, чрез която ще се проверява дали подаденото число е положително, отрицателно или нула. От примерите виждаме, че има три случая - числото е по-голямо от нула, равно на нула или по-малко от нула, което означава, че ще направим три проверки в тялото на функцията.
Следващата ни стъпка е да прочетем входното число и да извикаме новата функция:
Тествайте решението си тук: https://judge.softuni.org/Contests/Practice/Index/1063#1.
Езикът Python позволява използването на незадължителни параметри. Това позволява пропускането на някой параметри при извикването на функцията. Декларирането им става чрез осигуряване на стойност по подразбиране в декларацията на съответния параметър.
Следният пример онагледява употребата на незадължителните параметри:
Показаната функция print_numbers(…)
може да бъде извикана по няколко начина:
При първото извикване на функцията ще се използват параметрите start = 5
, end = 10
. Второто извикване - параметрите start = 0
, end = 15
. Третото извикване - параметрите start = 0
, end = 100
. А четвъртото извикване ще използва параметрите start = 35
и end = 45
.
Да се създаде функция, която принтира триъгълник, както е показано в примерите.
Вход | Изход | Вход | Изход |
---|---|---|---|
3 | 1 1 2 1 2 3 1 2 1 |
4 | 1 1 2 1 2 3 1 2 3 4 1 2 3 1 2 1 |
Преди да създадем функция за принтиране на един ред с дадени начало и край, прочитаме входното число от конзолата. След това избираме смислено име за функцията, което описва целта ѝ, например print_line
, и я имплементираме:
От задачите за рисуване на конзолата си спомняме, че е добра практика да разделяме фигурата на няколко части. За наше улеснение ще разделим триъгълника на три части - горна, средна и долна част.
Следващата ни стъпка е с цикъл да разпечатаме горната половина от триъгълника:
След това разпечатваме средната линия:
Накрая разпечатваме долната част от триъгълника, като този път стъпката на цикъла намалява:
Тествайте решението си тук: https://judge.softuni.org/Contests/Practice/Index/1063#2.
Да се нарисува на конзолата запълнен квадрат със страна N, както е показно в примерите.
Вход | Изход | Вход | Изход |
---|---|---|---|
4 | -------- -\/\/\/- -\/\/\/- -------- |
5 | ---------- -\/\/\/\/- -\/\/\/\/- -\/\/\/\/- ---------- |
Първата ни стъпка е да прочетем входа от конзолата. След това трябва да създадем функция, която ще принтира първия и последен ред, тъй като те са еднакви. Нека не забравяме, че трябва да ѝ дадем описателно име и да ѝ зададем като параметър дължината на страната:
Следващата ни стъпка е да създадем функция, която ще рисува на конзолата средните редове. Отново задаваме описателно име, например print_middle_row
:
Накрая извикваме създадените функции, за да нарисуваме целия квадрат:
Тествайте решението си тук: https://judge.softuni.org/Contests/Practice/Index/1063#3.
До момента разгледахме функции, които извършват дадено действие, например отпечатване на даден текст, число или фигура на конзолата. Освен този тип функции, съществуват и такива, които могат да връщат някакъв резултат от своето изпълнение - например резултатът от умножението на две числа. Именно тези функции ще разгледаме в следващите редове.
За да върнем резултат от функция, използваме оператора return
. Той трябва да бъде използван в тялото на функцията и указва на програмата да спре изпълнението си и да върне на извиквача на функцията определена стойност, която се определя от израза след въпросния оператор return
. В примера по-долу имаме функция, която чете две имена от конзолата, съединява ги и ги връща като резултат:
Операторът return
може да бъде използван и във функции, които не връщат резултат - след оператора не трябва да има израз. Изпълнението му води до това функцията да спре изпълнението си, без да връща никаква стойност. В този случай употребата на return
е единствено за прекратяване на изпълнението на функцията. Възможно е и операторът return
да бъде използван на повече от едно място в тялото на функцията.
В примера по-долу имаме функция, която сравнява две числа и връща резултат съответно -1
, 0
или 1
според това дали първият параметър е по-малък, равен или по-голям от втория параметър, подаден на функцията. Функцията използва ключовата дума return
на три различни места, за да върне три различни стойности според логиката на сравненията на числата:
Важно е да отбележим, че резултатът, който се връща от функцията, може да бъде от различен тип - низ, цяло число, число с плаваща запетая и т.н.
След оператор return
в дадена функция, изпълнението ѝ се прекратява и продължава на мястото, от където е извикана функцията. Ако след оператора return
има други инструкции, то те няма да бъдат изпълнени. Някои редактори, в това число и PyCharm, ще ви информират чрез предупрежение:
След като дадена функция е изпълнена и върне стойност, то тази стойност може да се използва по няколко начина. Първият е да присвоим резултата като стойност на променлива:
Вторият е резултатът да бъде използван в израз:
Третият е да подадем резултата от работата на функцията към друга функция чрез параметър:
Да се напише функция, която изчислява лицето на триъгълник по дадени основа и височина и връща стойността му.
Вход | Изход |
---|---|
3 4 |
6 |
Първо създаваме функция, която да изчислява лицето на базата на две променливи - дължината на страната a и височината h:
Следващата ни стъпка е да прочетем входните данни и да извикаме новата функция с тях. Резултатът записваме в подходяща променлива и извеждаме на екрана:
Тествайте решението си тук: https://judge.softuni.org/Contests/Practice/Index/1063#4.
Да се напише функция, която изчислява и връща резултата от повдигането на число на дадена степен.
Вход | Изход | Вход | Изход |
---|---|---|---|
2 8 |
256 | 3 4 |
81 |
Първата ни стъпка отново ще е да прочетем входните данни от конзолата. Следващата стъпка е да създадем функция, която ще приема два параметъра (числото и степента) и ще връща като резултат число от тип float
:
След като сме направили нужните изчисления, ни остава да извикаме дефинираната функция и да отпечатаме резултата.
Тествайте решението си тук: https://judge.softuni.org/Contests/Practice/Index/1063#5.
До тук разгледахме функции, които не връщат стойности и функции, които връщат една единствена стойност. В практиката често се срещат случаи, в които се нуждаем дадена функция да върне повече от една стойност като резултат.
За целта при използване на оператора return
в езика Python отделяме стойностите, които искаме да върнем, със запетая. Следната функция приема за параметри две целочислени числа (x
и y
) и връща две стойности - резултата от целочислено деление на двете числа и остатъка от делението им:
Извикването на функцията става по същия начин както и за функциите, които не връщат стойности или връщат една единствена стойност. За да използваме стойностите върнати от функцията, то можем да присвоим резултатите на няколко променливи, отделени със запетая, както е показано в примера със a
и b
. След изпълнението на този пример, a
ще съдържа стойността 3
, а b
- стойността 4
.
В много езици за програмиране една и съща функция може да е декларирана в няколко варианта с еднакво име и различни параметри. Това е известно с термина "function overloading" (или "method overloading"). Езикът за програмиране Python не позволява дефиниране на варианти на функции, но подобна функционалност може да бъде постигната с представените по-рано незадължителни параметри.
В програмирането начинът, по който се идентифицира една функция, е чрез двойката елементи от декларацията ѝ – име на функцията и списък от нейните параметри. Тези два елемента определят нейната спецификация, така наречена още сигнатура на функцията:
В този пример сигнатурата на функцията е нейното име print_name
, както и нейният параметър name
.
Ако в програмата ни има функции с еднакви имена, но с различни параметри, то казваме, че имаме варианти на функции (function или method overloading). Езикът за програмиране Python не позволява дефинирането на две функции с едно и също име.
Различни варианти за извикване на една функция в езика Python може да бъде постигнато чрез използването на незадължителни параметри, или по-конкретно - чрез предоставянето на стойности по подразбиране за дадени параметри. Нека разгледаме примера от по-рано за функция с няколко незадължителни параметъра:
Както вече видяхме, можем да извикваме тази функция по-различни начини, които наподобяват различни варианти на функцията:
Нека разгледаме следния пример за функция, която изчислява лице на окръжност:
Виждаме, че в този код, във функцията circle_circumference(…)
има друга декларирана функция circle_diameter(…)
. Тя се нарича вложена функция (nested function) или още - локална функция. Вложените функции могат да се декларират във всяка една функция и са видими и могат да бъдат извиквани само в тази функция. В примера по-горе функцията circle_diameter(…)
може да бъде извикана само от тялото на функцията circle_circumference(…)
, но не и извън него.
С времето и практиката ще открием, че когато пишем код, често се нуждаем от функции, които бихме използвали само един път, или пък нужната ни функция става твърде дълга. По-нагоре споменахме, че когато една функция съдържа в себе си прекалено много редове код, то той става труден за поддръжка и четене. В тези случаи на помощ идват вложените функции - те предоставят възможност в дадена функция да се декларира друга функция, която ще бъде използвана например само веднъж. Това спомага кодът ни да е по-добре подреден и по-лесно четим, което от своя страна спомага за по-бърза корекция на евентуална грешка в кода и намалява възможността за грешки при промени в програмната логика.
Нека отново разгледаме примера от по-горе:
В този пример, функцията circle_diameter(…)
е вложена функция, тъй като е декларирана в тялото на функцията circle_circumference(…)
. Това означава, че функцията circle_diameter(…)
може да бъде използвана само във функцията circle_circumference(…)
, но не и извън нея. Ако се опитаме да извикваме функцията circle_diameter(…)
извън функцията circle_circumference(…)
, това ще доведе до грешка при изпълнението на програмата.
Вложените функции имат достъп до променливите, които се използват в съдържащата ги функция. В примера по-горе променливата pi
може да бъде използвана от тялото на функцията circle_diameter(…)
. Тази особеност на вложените функции ги прави много удобни помощници при решаването на дадена задача. Те спестяват време и код, които иначе бихме вложили, за да предаваме на вложените функции параметри и променливи, които се използват в функциите, в които са вложени.
В тази част ще се запознаем с някои утвърдени практики при работа с функции, свързани с именуването, подредбата на кода и неговата структура.
Когато именуваме дадена функция е препоръчително да използваме смислени имена. Тъй като всяка функция отговаря за някаква част от нашия проблем, то при именуването ѝ трябва да вземем предвид действието, което тя извършва, т.е. добра практика е името да описва нейната цел.
В езика Python е прието имената на функциите да се изписват с малки букви, като отделните думи се отделят с долна черта _
. Добра практика е името на функцията да е съставено от глагол или от двойка: глагол и съществително име.
Няколко примера за коректно именуване на функции:
find_student
load_report
sine
Няколко примера за лошо именуване на функции:
Method1
DoSomething
Handle_Stuff
SampleMethod
DIRTYHack
Ако не можем да измислим подходящо име, то има голяма вероятност функцията да решава повече от една задача или да няма ясно дефинирана цел. В такива случай е добре да помислим как да я разделим на няколко отделни функции.
При именуването на параметрите на функции важат почти същите правила, както и при самите функции. Разликите тук са, че за имената на параметрите е добре да използваме съществително име или двойка от прилагателно и съществително име. Трябва да отбележим, че е добра практика името на параметъра да указва каква е мерната единица, която се използва при работа с него.
Няколко примера за коректно именуване на параметри:
first_name
report
speed_kmh
users_list
font_size_in_pixels
font
Няколко примера за некоректно именуване на параметри:
p
p1
p2
populate
LastName
lastName
Нека отново припомним, че една функция трябва да изпълнява само една точно определена задача. Ако това не може да бъде постигнато, то тогава трябва да помислим как да разделим функцията на няколко отделни такива. Както казахме, името на функцията трябва точно и ясно да описва нейната цел. Друга добра практика в програмирането е да избягваме функции, по-дълги от екрана ни (приблизително). Ако все пак кода стане много обемен, то е препоръчително функцията да се раздели на няколко по-кратки, както в следния пример:
При писането на функции трябва да внимаваме да спазваме коректна индентация (отместване навътре с една табулация). В езикът Python грешната индентация много често автоматично води до грешна програмата или такава, която не може да бъде изпълнена.
Пример за правилно форматиран Python код:
Пример за некоректно форматиран Python код (затова и последният ред е подчертан в червено):
Друга добра практика при писане на код е да оставяме празен ред след циклите и условните конструкции и два празни реда след дефиницията на функции. Също така, опитвайте да избягвате да пишете дълги редове и сложни изрази. С времето ще установите, че това подобрява четимостта на кода и спестява време.
В тази глава се запознахме с базовите концепции при работа с фунции:
- Научихме, че целта на функциите е да разделят големи програми с много редове код на по-малки и ясно обособени задачи.
- Запознахме се със структурата на функциите, как да ги декларираме и извикваме по тяхното име.
- Разгледахме примери за функции с параметри и как да ги използваме в нашата програма.
- Научихме какво представляват сигнатурата и връщаната стойност на функцията, както и какво представлява операторът
return
. - Запознахме се с добрите практики при работа с функции - как да именуваме функциите и техните параметри, как да форматираме кода и други.
За да затвърдим работата с функции, ще решим няколко задачи. В тях се изисква да напишете функция с определена функционалност и след това да я извикате като ѝ подадете данни, прочетени от конзолата, точно както е показано в примерния вход и изход.
Да се напише функция, която получава като параметър име и принтира на конзолата "Hello, <name>!".
Вход | Изход |
---|---|
Peter | Hello, Peter! |
Дефинираме функция print_name(name)
и я имплементираме, след което прочитаме от конзолата низ (името на човек) и извикаваме функцията като ѝ подаваме прочетеното име.
Тествайте решението си тук: https://judge.softuni.org/Contests/Practice/Index/1063#7.
Да се създаде функция get_min(a, b)
, която връща по-малкото от две числа. Да се напише програма, която чете като входни данни от конзолата три числа и печата най-малкото от тях. Да се използва функцията get_min(…)
, която вече е създадена.
Вход | Изход | Вход | Изход |
---|---|---|---|
1 2 3 |
1 | -100 -101 -102 |
-102 |
Дефинираме функция get_min(a, b)
и я имплементираме, след което я извикваме от програмата, както е показано по-долу. За да намерим минимума на три числа, намираме първо минимума на първите две от тях и след това минимума на резултата и третото число:
minimum = get_min(get_min(number1, number2), number3)
Тествайте решението си тук: https://judge.softuni.org/Contests/Practice/Index/1063#8.
Да се напише функция repeat_string(str, count)
, която получава като параметри променлива от тип низ и цяло число N и връща низа, повторен N пъти. След това резултатът да се отпечата на конзолата.
Вход | Изход | Вход | Изход |
---|---|---|---|
str 2 |
strstr | roki 6 |
rokirokirokirokirokiroki |
Допишете функцията по-долу като добавите съединяването на входния низ към резултата в цикъла:
Тествайте решението си тук: https://judge.softuni.org/Contests/Practice/Index/1063#9.
Да се напише функция find_nth_digit(number, index)
, която получава число и индекс N като параметри и печата N-тата цифра на числото (като се брои от дясно на ляво, започвайки от 1). След това, резултатът да се отпечата на конзолата.
Вход | Изход | Вход | Изход | Вход | Изход |
---|---|---|---|---|---|
83746 2 |
4 | 93847837 6 |
8 | 2435 4 |
2 |
За да изпълним алгоритъма, ще използваме while
цикъл, докато дадено число не стане 0. На всяка итерация от while
цикъла ще проверяваме дали настоящият индекс на цифрата не отговаря на индекса, който търсим. Ако отговаря, ще върнем като резултат цифрата на индекса (number % 10
). Ако не отговаря, ще премахнем последната цифра на числото (number = number / 10
). Трябва да следим коя цифра проверяваме по индекс (от дясно на ляво, започвайки от 1). Когато намерим цифрата, ще върнем индекса.
Тествайте решението си тук: https://judge.softuni.org/Contests/Practice/Index/1063#10.
Да се напише функция integer_to_base(number, to_base)
, която получава като параметри цяло число и основа на бройна система и връща входното число, конвертирано към посочената бройна система. След това, резултатът да се отпечата на конзолата. Входното число винаги ще е в бройна система 10, а параметърът за основа ще е между 2 и 10.
Вход | Изход | Вход | Изход | Вход | Изход |
---|---|---|---|---|---|
3 2 |
11 | 4 4 |
10 | 9 7 |
12 |
За да решим задачата, ще декларираме една променлива, в която ще пазим резултата. След това трябва да изпълним следните изчисления, нужни за конвертиране на числото:
- Изчисляваме остатъка от числото, разделено на основата.
- Вмъкваме остатъка от числото в началото на низа, представящ резултата.
- Разделяме числото на основата.
- Повтаряме алгоритъма, докато входното число не стане 0.
Допишете липсващата логика във функцията по-долу:
Тествайте решението си тук: https://judge.softuni.org/Contests/Practice/Index/1063#11.
Да се напише програма, която прочита цяло число N и на следващите редове въвежда N съобщения (като за всяко съобщение се прочитат по няколко реда). За всяко съобщение може да се получат различен брой параметри. Всяко съобщение започва с message_type
: success
, warning
или error
:
- Когато
message_type
еsuccess
да се четатoperation
+message
(всяко на отделен ред). - Когато
message_type
еwarning
да се чете самоmessage
. - Когато
message_type
еerror
да се четатoperation
+message
+errorCode
(всяко на отделен ред).
На конзолата да се отпечата всяко прочетено съобщение, форматирано в зависимост от неговия message_type
. Като след заглавния ред за всяко съобщение да се отпечатат толкова на брой символа =
, колкото е дълъг съответният заглавен ред и да се сложи по един празен ред след всяко съобщение (за по-детайлно разбиране погледнете примерите).
Задачата да се реши с дефиниране на четири функции: show_success_message()
, show_warning_message()
, show_error_message()
и read_and_process_message()
:
Вход | Изход |
---|---|
4 error credit card purchase Invalid customer address 500 warning Email not confirmed success user registration User registered successfully warning Customer has not email assigned |
Error: Failed to execute credit card purchase. ============================================== Reason: Invalid customer address. Error code: 500. Warning: Email not confirmed. ============================= Successfully executed user registration. ======================================== User registered successfully. Warning: Customer has not email assigned. ========================================= |
Дефинираме и имплементираме посочените четири функции в условието.
В функцията read_and_process_message()
прочитаме типа съобщение от конзолата и според прочетения тип прочитаме останалите данни (който може да са още един два или три реда). След това извикваме съответния метод за печатане на съответния тип съобщение.
Тествайте решението си тук: https://judge.softuni.org/Contests/Practice/Index/1063#12.
Да се напише функция letterize(number)
, която прочита цяло число и го разпечатва с думи на английски език според условията по-долу:
- Да се отпечатат с думи стотиците, десетиците и единиците (и евентуални минус) според правилата на английския език.
- Ако числото е по-голямо от 999, трябва да се принтира "too large".
- Ако числото е по-малко от -999, трябва да се принтира "too small".
- Ако числото е отрицателно, трябва да се принтира "minus" преди него.
- Ако числото не е съставено от три цифри, не трябва да се принтира.
Вход | Изход | Вход | Изход |
---|---|---|---|
3 999 -420 1020 |
nine-hundred and ninety nine minus four-hundred and twenty too large |
2 15 350 |
fifteen three-hundred and fifty |
Вход | Изход | Вход | Изход |
---|---|---|---|
4 311 418 509 -9945 |
three-hundred and eleven four-hundred and eighteen five-hundred and nine too small |
3 500 123 9 |
five-hundred one-hundred and twenty three nine |
Можем първо да отпечатаме стотиците като текст - (числото / 100) % 10
, след тях десетиците - (числото / 10) % 10
и накрая единиците - (числото % 10)
.
Първият специален случай е когато числото е точно закръглено на 100 (напр. 100, 200, 300 и т.н.). В този случай отпечатваме "one-hundred", "two-hundred", "three-hundred" и т.н.
Вторият специален случай е когато числото, формирано от последните две цифри на входното число, е по-малко от 10 (напр. 101, 305, 609 и т.н.). В този случай отпечатваме "one-hundred and one", "three-hundred and five", "six-hundred and nine" и т.н.
Третият специален случай е когато числото, формирано от последните две цифри на входното число, е по-голямо от 10 и по-малко от 20 (напр. 111, 814, 919 и т.н.). В този случай отпечатваме "one-hundred and eleven", "eight-hundred and fourteen", "nine-hundred and nineteen" и т.н.
Тествайте решението си тук: https://judge.softuni.org/Contests/Practice/Index/1063#13.
Да се напише функция encrypt(letter)
, който криптира дадена буква по следния начин:
- Вземат се първата и последна цифра от ASCII кода на буквата и се залепят една за друга в низ, който ще представя резултата.
- Към началото на стойността на низа, който представя резултата, се залепя символа, който отговаря на следното условие:
- ASCII кода на буквата + последната цифра от ASCII кода на буквата.
- След това към края на стойността на низа, който представя резултата, се залепя символа, който отговаря на следното условие:
- ASCII кода на буквата - първата цифра от ASCII кода на буквата.
- Функцията трябва да върне като резултат криптирания низ.
Пример:
- j → p16i
- ASCII кодът на j e 106 → Първа цифра - 1, последна цифра - 6.
- Залепяме първата и последната цифра → 16.
- Към началото на стойността на низа, който представя резултата, залепяме символа, който се получава от сбора на ASCII кода + последната цифра → 106 + 6 → 112 → p.
- Към края на стойността на низа, който представя резултата, залепяме символа, който се получава от разликата на ASCII кода - първата цифра → 106 - 1 → 105 → i.
Използвайки функцията, описана по-горе, да се напише програма, която чете поредица от символи, криптира ги и отпечатва резултата на един ред.
Приемаме, че входните данни винаги ще бъдат валидни. От конзолата трябва да се прочетат входните данни, подадени от потребителя – цяло число N, следвани от по един символ на всеки от следващите N реда.
Да се криптират символите и да се добавят към криптирания низ. Накрая като резултат трябва да се отпечата криптиран низ от символи като в следващия пример:
- S, o, f, t, U, n, i → V83Kp11nh12ez16sZ85Mn10mn15h
Вход | Изход |
---|---|
7 S o f t U n i |
V83Kp11nh12ez16sZ85Mn10mn15h |
Вход | Изход |
---|---|
7 B i r a H a x |
H66<n15hv14qh97XJ72Ah97xx10w |
Създаваме една променлива result
, в която ще се пази стойността на резултата, и ѝ присвояваме първоначална стойност ""
(празен низ). Трябва да се завърти цикъл n
пъти, като на всяка итерация към променливата, в която пазим стойността на резултата, ще прибавяме криптирания символ.
За да намерим първата и последната цифри от ASCII кода, ще използваме алгоритъма, който използвахме за решаване на задача "N-та цифра", а за да създадем низа, ще процедираме както в задачата "Число към бройна система".
Тествайте решението си тук: https://judge.softuni.org/Contests/Practice/Index/1063#14.