Автоматизирай Това Начало на книгата

Управление на изпълнението

Вече е ясно как се съставят отделните инструкции и че програмата е просто поредица от инструкции. Но истинската сила на програмирането не е в простото последователно изпълнение на инструкции. Програмата може да провери резултатът от даден израз и да прецени дали да пропусне инструкции, да ги повтори или да избере една от няколко инструкции, която да изпълни. Всъщност, почти никога не трябва програма, която да започне от първия ред код и просто да изпълни всеки ред до края. Условните конструкции (flow control statements) позволяват на Python да реши при кои условия кои инструкции да се изпълнят

Тези условни конструкции са аналогично на блок схемите. Следва блоксхема на кода, който ще се обсъжда по-долу. Това е блок схема за вземане на решение за действие, ако вали. Трябва да се проследи пътя по стрелките, започвайки от Старт до Край :

Блок-схема на програма
Блок схема за действие по време на дъжд

В блоксхемите обикновено има повече от един начин за стигане до края, започвайки от началото. Същото важи и за редовете код в компютърна програма. В блоксхемите такива разклонения се представят с ромбове, докато останалите стъпки са правоъгълници. Началната и крайната стъпки се представят с закръглени правоъгълници.

Предусловие за научаването на условните конструкции е знанието как да се представят възможностите Да и Не. Също така трябва да се разбере как се пишат разклонения като код на Python. За тази цел се започва с булеви стойности, оператори за сравнение и булеви оператори.

Булеви стойности

Целите числа, числата с плаваща запетая и символните низове имат безкраен брой възможни стойности. За разлика от тях Булевият (Boolean) тип данни има само две стойности - True (истина) и False (лъжа). Булев тип данни е кръстен на математика Джордж Бул. При писане на Python код булевите стойности True и False са без кавички и започват с главна буква. Следва пример от интерактивната конзола. (Нарочно някои инструкции са сгрешени, за да покажат съобщения за грешка) :

➊>>> spam = True
>>>spam
True
➋>>> true
NameError Traceback (most recent call last)
in
----> 1 true
NameError: name 'true' is not defined
➌>>> True = 2 + 2
File "", line 1
   True = 2 + 2
                        ^
SyntaxError: can't assign to keyword

Булеви стойности могат да се използват в изрази, както и да се запазват в променливи ➊ , както всички останали стойности. Python дава грешка, ако не се използва главна буква ➋ или True или False се използват за имена на променливи ➌ .

Оператори за сравнение

Операторите за сравнение (comparison operators или relational operators) сравняват две стойности и се пресмятат до булева стойност. Следващата таблица показва операторите за сравнение :

Оператори за сравнение
Оператор Значение
== Равно на
!= Не е равно на
< По-малко от
> По-голямо от
<= По-малко или равно на
>= По-голямо или равно на

Тези оператори се пресмятат до True или False спрямо стойностите, които им се подават. Ето примери с операторите == и !=:

>>> 42 == 42
True
>>> 42 == 99
False
>>> 2 != 3
True
>>> 2 != 2
False

Както се очаква, == (равно на) се пресмята като истина (True) ако от двете страни има еднакви стойности. Операторът != (не е равно на) е True, когато двете стойности са различни. Операторите == и != работят със стойности от всякакъв тип :

>>> 'hello' == 'hello'
True
>>> 'здравей' == 'здравей'
True
>>> 'здравей' == 'Здравей'
False
>>> 'куче' != 'котка'
True
>>> True == True
True
>>> True != False
True
>>> 42 == 42.0
True
➊ >>> 42 == '42'
False

Трябва да се отбележи, че число никога не е равно на символен низ. Изразът 42 == '42' ➊ се пресмята до False, защото за Python числото 42 е различно от символния низ '42'.

Операторите <, >, <= и >= работят правилно само с числа.

>>> 42 < 100
True
>>> 42 > 100
False
>>> 42 < 42
False
>>> eggCount = 42
➊ >>> eggCount <= 42
True
>>> myAge = 29
➋>>> myAge >= 10
True

Често операторите за сравнение се използват за сравняване на стойността на променлива с друга стойност. Такива са примерите ➊ eggCount <= 42 и ➋ myAge >= 10. (Все пак вместо 'dog' != 'cat' може да се напише директно True.) Още примери има в частта, свързана с условните конструкции.

Логически оператори

Има три логически оператора ( and (логическо "И"), or (логическо "ИЛИ") и not (логическо отрицание)) се използват за операции с булеви стойности. Те също се пресмятат до булева стойност, както операторите за сравнение. Следва подробно разглеждане на тези оператори, започвайки с оператора and.

Двуаргументни (Binary, бинарни) логически оператори

Операторите and и or винаги приемат две булеви стойности (или изрази), затова те се наричат двуаргументни (binary) оператори. Операторът and се пресмята до израза True само ако и двете булеви стойности са True. Иначе се пресмята до False. Ето няколко примера от интерактивната конзола :

>>> True and True
True
>>> True and False
False

За анализиране на булеви изрази се използват таблици на истинността (truth table). Такава таблица показва всеки възможен резултат на даден булев израз. За пример следва таблицата на истинността за оператора and :

Таблица на истинността на опратора and
Израз Пресмята се до ...
True and True True
True and False False
False and True False
False and False False

От друга страна операторът or се пресмята до True ако някоя от двете булеви стойности е True. Ако и двете са False резултатът е False.

>>> False or True
True
>>> False or False
False

В следващата таблица на истинност са показани всички възможни резултати на опратора or :

Таблица на истинността на опратора or
Израз Пресмята се до ...
True or True True
True or False True
False or True True
False or False False

Оператор not

За разлика от and и or, операторът not работи само с една булева стойност (или израз). По тази причина той се нарича едноаргументен (унарен, unary) оператор. Операторът not винаги се пресмята до противоположната булева стойност.

>>> not True
False
➊ >>> not not not not True
True

Операторите not могат да се натрупват ➊, както в българския език могат да се натрупват отрицания. В истинска програма никога няма необходимост да се изполва. Следва таблицата на истинността на not :

Таблица на истинността на опратора not
Израз Пресмята се до ...
not True False
not False True

Комбиниране на булеви оператори и сравнения

Операторите за сравнение се пресмятат до булеви стойности, така че могат да се използват в изрази заедно с булеви оператори.

Операторите and, or и not са наречени булеви, защото работят с булевите стойности True и False. Изразите от типа на 4 < 5 не използват булеви стойности, но се пресмятат до булева стойност. Това може да се провери в интерактивната конзола :

>>> (4 < 5) and (5 < 6)
True
>>> (4 < 5) and (9 < 6)
False
>>> (1 == 2) or (2 == 2)
True

Компютърът пресмята първо левия израз, после десния израз. След като всеки израз е сведен до булева стойност, след това целия израз се пресмята до булева стойност. Процесът на пресмятане на (4 < 5) and (5 < 6) е следния:

Процес на пресмятане

В един израз може да има комбинирани няколко булеви оператора и сравнения:

>>> 2 + 2 == 4 and not 2 + 2 == 5 and 2 * 2 == 2 + 2
True

Булевите оператори също имат приоритет, както алгебричните. Python първо пресмята алгебричните оператори, след тях операторите за сравнение, след това оператори not, оператори and и накрая операторите or.

Елементи на условните конструкции

Условните конструкции често започват с условие (condition), последвано от парче (блок) код, наречен тяло (клауза, clause). Следва кратко описание какво е условие и какво е блок от код.

Условия

По-горните булеви изрази могат да се считат за условия, които са същото като изрази. Условие е просто специфично название в контекста на условните изрази. Условията винаги се пресмятат до булева стойност, True или False. Условната конструкция преценява какво точно да извърши според резултатът от пресмятането на условието.

Блокове код

Няколко реда код на Python могат да се групират в блок. Началото и края на блок могат да се определят от индентацията(отместване) на редовете код. Има три правила за блоковете:

  • Блокът започва с увеличаване на отместването(индентацията).
  • Един може да съдържа други блокове.
  • Блокът завършва с намаляване на отместването до нула или до индентацията на по-големия блок.

Блоковете са по-лесни за разбиране с пример :

name = 'Мария'
password = 'риба меч'
if name == 'Мария':
    ➊ print('Здравей, Мария')
    if password == 'риба меч':
        ➋ print('Достъп разрешен !')
    else:
        ➌ print('Грешна парола!')

Първият блок код ➊ започва на реда print('Здравей, Мария') и съдържа всички следващи редове. В този блок има друг блок ➋, който е само от един ред print('Достъп разрешен !'). Третият блок ➌ също е от един ред : print('Грешна парола!').

Изпълнение на програмата

В предната глава има програма hello.py, която се изпълнява от горе до долу, ред след ред. Програмата изпълнява (или само изпълнява) определена текуща команда. Ако се принтира на хартия кода на една програма може с пръст да се следи реда, който се изпълнява. Този пръст ще сочи командата, която се изпълнява.

Обаче не всички програми се изпълняват с просто преминаване към следващия ред. Един пръст, следящ изпълнението на програма с условни конструкции, вероятно ще прескача по кода спрямо условията и може да пропусне цели блокове код.

Условни конструкции

Най-важната част от управлението на изпълнението са самите условни конструкции. Конструкциите са ромбовете в блоксхемата по-горе и представляват решенията, които програмата трябва да вземе.

Конструкция if

Най-често срещаната условна конструкция е if. Тялото (клаузата) на if конструкцията ще се изпълни, ако условието е True (истина). Ако условието не е изпълнено - тялото на конструкцията се пропуска.

С едно изречение, if конструкцията може да се чете като "Ако условието е изпълнено - изпълни кода на тялото." В езика Python конструкцията се състои от :

  • Запазената дума if
  • Условие (израз, който се пресмята до истина или неистина, True или False)
  • Двуеточие
  • Блок от код, започващ на следващия ред (тяло или if клауза)

За нагледен пример следва код, който проверява дали име е Алиса. (стойността на променливата name е присвоена някога по-рано)

if name == 'Алиса':
    print('Здравей, Алиса.')

Всички условни конструкции завършват с двуеточие, последвано от нов блок от код(тялото). Тялото на тази if конструкция е блок с един ред : print('Здравей, Алиса.'). На следващата картинка е показана блоксхема на кода :

Блок-схема на if конструкция
Блок схема на if конструкция

Конструкция else

Тялото на if може да бъде последвано от конструкция else. Тялото на else се изпълнява само ако условието на if не е изпълнено. С едно изречение else се описва като "Ако условието е изпълнено - изпълни този код. Иначе - изпълни онзи код." Конструкцията else не съдържа условие. Тя се състои от :

  • Запазената дума else
  • Двуеточие
  • Блок от код, започващ на следващия ред (тяло или else клауза)

В примера с Алиса може да се добави код, който показва различен поздрав, ако името не е Алиса :

if name == 'Алиса':
    print('Здрасти, Алиса.')
else:
    print('Здравей, страннико.')

Блоксхемата на този код е :

Блок-схема на else конструкция
Блок схема на else конструкция

Конструкция elif

Само една от клаузите if или else ще се изпълни. Но има случаи, когато е необходимо да се изпълни една от много клаузи. Конструкцията elif (съкратено от "else if", "иначе ако") винаги е предхождана от if или друга elif конструкция. Тя предлага друго условие, което да се провери само ако всички предишни условия не са изпълнени. Конструкцията elif се състои от:

  • Запазената дума elif
  • Условие (израз, който се пресмята до истина или неистина, True или False)
  • Двуеточие
  • Блок от код, започващ на следващия ред (тяло или elif клауза)

В примера за проверка на име може да се добави конструкция elif :

if name == 'Алиса':
    print('Здрасти, Алиса.')
elif age < 12:
    print('Дете, ти не си Алиса.')

Тук се проверява възрастта и се показва различен поздрав ако е под 12. Следва блоксхема на програмата :

Блок-схема на elif конструкция
Блок схема на elif конструкция

Тялото на elif се изпълнява ако age < 12 е изпълнено, а name == 'Алиса' не е изпълнено. Ако и двете условия не са изпълнени, нито една от клаузите няма да се изпълни. Няма гаранция, че някоя клауза ще бъде изпълнена. При няколко elif конструкции ще се изпълни най-много една клауза. Когато някое условие в конструкцията е изпълнено, останалите elif клаузи се пропускат автоматично. За пример следва код, записан в редактора като vampire.py :

name = 'Влад'
age = 3000
if name == 'Алиса':
    print('Здрасти, Алиса.')
elif age < 12:
    print('Дете, ти не си Алиса.')
elif age > 2000:
    print('За разлика от теб Алиса не е безсмъртен вампир')
elif age > 100:
    print('Дядо, ти не си Алиса')

Тук са добавени още две elif конструкции, които да поздравяват различно според стойността на age. Следва блок схемата на тази програма :

Блок-схема на elif конструкциите в програмата vampire.py
Блок-схема на elif конструкциите в програмата vampire.py

Редът на elif условията има голямо значение. Пренареждането им може да доведе до проблем (бъг). Трябва да се запомни, че когато едно условие на elif е изпълено, останалите автоматично се пропускат. Ако някои elif условия в програмата vampire.py се разменят - ще се стигне до проблем. Ето примерна програма ( vampire2.py), в която е направена размяна :

name = 'Влад'
age = 3000
if name == 'Алиса':
    print('Здрасти, Алиса.')
elif age < 12:
    print('Дете, ти не си Алиса.')
➊ elif age > 100:
    print('Дядо, ти не си Алиса')
elif age > 2000:
    print('За разлика от теб Алиса не е безсмъртен вампир')

Нека преди началото на изпълнението в променливата age съдържа стойността 3000. Може би се очаква програмата да покаже текста 'За разлика от теб Алиса не е безсмъртен вампир'. Всъщност, тъй като условието ➊ age > 100 е изпълнено (все пак, 3000 е повече от 100 ), показаният текст е 'Дядо, ти не си Алиса'. Останалите elif се пропускат автоматично. Трябва да се запомни, че най-много една от клаузите ще бъде изпълнена и редът има значение !

На следващата картинка е показана блоксхемата на променения код. Трябва да се отбележи смяната на местата на ромбовете age > 100 и age > 2000.

Блок-схема на elif конструкциите в програмата vampire2.py
Блок-схема на elif конструкциите в програмата vampire2.py. Логически пътя с Х не може да се мине, защото ако възрастта е по-голяма от 2000, тя вече ще е била по-голяма от 100.

При нужда може да се добави else конструкция след последната elif конструкция. В такъв случай е гарантирано, че точно една клауза ще бъде изпълнена. Тялото на else се изпълнява ако нито едно условие не е изпълнено. Ето примера с Алиса, преработена да използва if, elif и else :

name = 'Влад'
age = 3000
if name == 'Алиса':
    print('Здрасти, Алиса.')
elif age < 12:
    print('Дете, ти не си Алиса.')
else:
    print('Нито си Алиса, нито си малко дете')

Записаната като littleKid.py програма може да се представи със следната блоксхема:

Блок-схема на програмата littleKid.py
Блок-схема на програмата littleKid.py

Този тип управление на изпълнението може да се опише като "Ако първото условие е изпълнено - извърши това. Иначе, ако второто условие е изпълнено - извърши онова. В краен случай - свърши нещо друго." При използването на конструкциите if, elif и else трябва да се правилата за подреждането им, за да се избегнат бъговете от програмата vampire2.py. Първо, винаги има само един if. Конструкциите elif следват if. Второ, ако трябва винаги да има изпълнена клауза, накрая на конструкциите завършва с else.

while Цикъл

Конструкцията while позволява многократното изпълнение на блок от код. Кодът в тялото на while ще се изпълнева, докато условието на while конструкцията е изпълнено. Конструкцията while се състои от :

  • Запазената дума while
  • Условие (израз, който се пресмята до истина или неистина, True или False)
  • Двуеточие
  • Блок от код, започващ на следващия ред (тяло или while клауза)

Конструкцията while изглежда като конструкция if. Разликата е в поведението. При if след тялото изпълнението преминава към първата команда след if конструкцията. При while се изпълнява тялото, а селд това програмата се връща в началото на конструкцията. По тази причина while конструкцията е цикъл.

Следва сравнение на конструкция if и цикъл while, които имат еднакво услоивие и тяло. Кодът на if конструкцията :

spam = 0
if spam < 5:
    print('Здравей, свят !')
    spam = spam + 1

Ето и кодът на while конструкцията:

spam = 0
while spam < 5:
    print('Здравей, свят !')
    spam = spam + 1

Двете конструкции си приличат - проверяват стойността на spam и показват съобщение, ако е по-малка от 5. Но при изпълнението на двете програми се получават различни разлияни резултати. При if конструкцията се принтира "Здравей, свят!". При while контрукцията "Здравей, свят!" се повтаря пет пъти ! Следват блоксхемите на двете програми, които обясняват какво става :

Блоксхема на if конструкцията
Блоксхема на if конструкцията
Блоксхема на while конструкцията
Блоксхема на while конструкцията

Кодът на if конструкцията проверява условието и принтира Здравей, свят ! веднъж. От друга страна while цикълът ще го принтира пет пъти. Цикълът спира след петия път, защото стойността на променливата spam се увеличава с единица при всяко завъртане на цикъла. Това означава, че тялото на цикъла ще се изпълни пет пъти, преди условието spam < 5 да не е изпълнено

В while цикъла условието се проверява в началото на всяко повторение (итерация, едно изпълнение на тялото на цикъла). Ако условието е изпълнено се изпълнява и тялото на цикъла. След това условието се проверява отново. Ако условието не е изпълнено тялото се пропуска и изпълнението на програмата продължава с кода след while конструкцията.

Досаден while цикъл

Следва кратка примерна програма(yourName.py), която постоянно иска да се въведе, буквално, име.

➊ name = ''
➋ while name != 'име':
    print('Въведи име.')
    ➌ name = input()
➍ print('Край!')

Първоначално програмата присвоява на променливата name ➊ празен низ. Това е направено с цел условието name != 'име' да е изпълнено и програмата да влезе в тялото на while конструкцията ➋.

Кодът в тялото иска потребителят да въведе име, което след това се привоява на променливата spam ➌. Това е последният ред в блока, така че изпълнението се връша в началото на while конструкцията, където отново се проверява условието. Ако стойността на name е различна от низа 'име', условието е изпълнено и отново се изпълнява тялото на while.

Когато потребителят въведе име, условието ще е 'име' != 'име', което се пресмята до False. Условието не е изпълнено и програмата не изпълнява тялото на цикъла, а продължава с останалата част от кода ➍. Следва блоксхемата на програмата yourName.py:

Блоксхема на програмата yourName.py
Блоксхема на програмата yourName.py

Ако програмата се стартира и няколко пъти се въведат различни от име имена ще се получи нещо като :

Въведи име.
test
Въведи име.
тест
Въведи име.
ime
Въведи име.
име
Край!

Тялото на while контрукцията ще се изпълнява, докато не се въведе име, което означава, че програмата може да не приключи никога. Извикването на input() позволява на потребителя да въведе правилния текст, с който програмата да излезе от цикъла и да продължи нататък. В други програми може условието да не зависи от промените, което ще доведе до проблем, Поради тази причина има начини за прекъсване на while цикъла.

Изразът break

Има начин за директно спиране на изпълнението на while цикъл. При достигане на израз break изпълнението веднага излиза от тялото на while. Изразът break се състои единствено от запазената дума break.

Използването на break е доста лесно. Следващата програма(yourName2.py) е равносилна на предишната, но използва break за приключване на цикъла:

➊ while True:
    print('Въведи име.')
    ➋ name = input()
    ➌ if name == 'име':
        ➍ break
➎ print('Край!')

Първият ред създава безкраен цикъл (infinite loop) - while цикъл с условие, което винаги е изпълнено (Все пак изразът True винаги е True). След като изпълнението на програмата влезе в този цикъл, можв да излезе само след достигане до break. Често срещан програмен бъг е създаването на безкраен цикъл, който никога не свършва.

Точно като предната програма, потребителят тябва да въведе име ➋. Следва разликата - в тялото на while цикъла има проверка(с if конструкция) ➌ дали name е равно на 'име'. Ако условието е изпълнено се стига до изпълнение на израза break ➍ и се излиза от цикъла. Следващата изпънена инструкция ще е print('Край!') ➎. Ако условието на if не е изпълнено, неговото тяло (съдържащо break) се пропуска и се стига до края на цикъла while. От тук изпълнението на програмата се връща в началото на while конструкцията ➊ и се започва нова итерация. Тъй като в условието има само булевата стойност True изпълнението продължава в тялото на цикъла и потребителят е отново подканен да въведе име. Следва блоксхемата на тази програма :

Блоксхема на програмата yourName2.py
Блоксхема на програмата yourName2.py, съдържаща безкраен цикъл. Пътят, отбелязан с Х, логически не може да се изпълни, защото условието на цикъла е винаги True.

Изразът continue

Изразът continue, подобно на break, се използва в цикъл. Когато изпълнението на програмата стигне до continue, програмата се връща в началото на цикъла и пресмята отново условието( все едно е достигнат края на тялото на цикъла).

Следва програма (swordfish.py), която използва continue, за да иска име и парола :

while True:
    print('Как се казваш ?')
    name = input()
    ➊ if name != 'Иво':
        ➋ continue
    print('Здравей, Иво. Каква е паролата? ( Подсказка: риба е)')
    ➌ password = input()
    if password == 'риба меч':
        ➍ break
➎ print('Достъп рарешен.')

Ако потребителят въведе име, различно от Иво ➊, изразът continue ➋ връща изпълнението на програмата в началото на цикъла. Тогава се пресмята наново условието, което винаги е изпълнено(True) и изпълнението продължава с тялото на цикъла. Потребителят стига до въвеждането на парола ➌ след въвеждане на правилното име. Ако въведената парола е риба меч се изпълнява break ➍ и изпълнението излиза от тялото на цикъла,принтира Достъп рарешен. ➎. При грешна парола изпълнението стига до края на цикъла, откъдето се връща в началото на цикъла. Следва блоксхемата на тази програма :

Блоксхема на програмата swordfish.py
Блоксхема на програмата swordfish.py. Пътят, отбелязан с Х, логически не може да се изпълни, защото условието на цикъла е винаги True.

При стартиране на програмата трябва да се въведе име. Програмата не пита за парола, освен ако не се въведе Иво. Програмата приключва след въвеждане на правилната парола:

Как се казваш ?
Киро
Как се казваш ?
Иво
Здравей, Иво. Каква е паролата? ( Подсказка: риба е)
Щука
Как се казваш ?
Иво
Здравей, Иво. Каква е паролата? ( Подсказка: риба е)
риба меч
Достъп рарешен.

Цикъл for и функцията range()

Цикълът while се изпълнява, докато условието му е True (откъдето идва името му - while се превежда "докато" на български). Това обаче не е удобно, ако даден код трябва да се изпълни определен брой пъти. За тази целта е по-лесно да се използва конструкцията for и функцията range().

В кода конструкция for изглежда нещо като for i in range(5): и се състои от :

  • Запазената дума for
  • Име на променлива
  • Запазената дума in
  • Извикване на метода range() с до три целочислени параметъра
  • Двуеточие
  • Блок от код, започващ на следващия ред (тяло или for клауза)

Следва кратка програма( fiveTimes.py ), която демонстрира for цикъл :

print('Името ми е')
for i in range(5):
    print('Дончо Пет Пъти (' + str(i) + ')')

Кодът в тялото на forцикъла ще се изпълни пет пъти. При първото изпълнение променливата i ще получи стойност 0. Извикването на функцията print() в тялото на цикъла ще принтира Дончо Пет Пъти (0). След като се изпълни тялото на цикъла, изпълнението се връща в началото на цикъла и for конструкцията увеличава стойността на i с единица. Така range(5) предизвиква пет изпълнения на тялото на цикъла, като i получава стойност съответно 0, след това 1, 2, 3 и накрая - 4. Стойността на променливата i се увеличава до, но не включително, целочислената стойност, подадена на range(). Блоксхемата на програмата fiveTimes.py изглежда по следния начин :

Блоксхема на програмата fiveTimes.py
Блоксхема на програмата fiveTimes.py.

При изпълнение на програмата тя принтира пет пъти Дончо Пет Пъти и стойността на i, преди да приключи цикъла.

Името ми е
Дончо Пет Пъти (0)
Дончо Пет Пъти (1)
Дончо Пет Пъти (2)
Дончо Пет Пъти (3)
Дончо Пет Пъти (4)

БЕЛЕЖКА

В цикъл for може да се използват break и continue. Изразът continue предизвиква изълнение на тялото на цикъла със следващта стойност на брояча. Действието е все едно изпълнението е стигнало до края на for цикъла и започва ново завъртане. Всъщност continue и break могат да се използват само в цикъл while или for. Питон генерира грешка, ако тези изрази се изполват на друго място.

Друг пример за for цикъл, вдъхновен от разказ за математика Карл Фридрих Гаус. Учителят на Гаус искал да даде на децата задача, с която да се занимават продължително време, така че им казал да съберат всички числа от 0 до 100. Младият Гаус измислил хитър начин, по който сметнал сумата за броени секунди. Една проста програма на Питон може да сметне сумата, дори без да се използват трикове.

➊ total = 0
➋ for num in range(101):
    ➌ total = total + num
➍ print(total)

Резултатът е 5050. В началото програмата присвоява стойност 0 на променливата total ➊. След това цикълът for ➋ изпълнява 100 пъти total = total + num ➌. При приключване на стоте завъртания на цикъла всяко число от 0 до 100 ще бъде добавено към total. Накрая стойността на totalсе принтира на екрана ➍. И на най-бавния компютър програмата ще приключи за по-малко от секунда.

(Малкият Гаус измислил начин за бързо решаване на задачата. Има 50 двойки числа, които имат сума 101 : 1 + 100, 2 + 99, 3 + 98 и така нататък до 50 + 51. Това са 50 двойки със сума 101. 50 х 101 е равно на 5050, значи сумата на числата от 0 до 100 е 5050. Умно дете!)

Еквивалентен while цикъл

Винаги може да се използва while цикъл вместо for цикъл. Просто понякога for цикълът е по-кратък. Програмата fiveTimes.py може да се пренапише с използване на while цикъл :

print('Името ми е')
i = 0
while i < 5:
    print('Дончо Пет Пъти (' + str(i) + ')')
    i = i + 1

Тази програма има същия резултат като fiveTimes.py, която използва for цикъл.

Аргументите на range() - начална стойност, гранична стойност и стъпка

range() е от функциите, които могат да бъдат извикани с няколко аргумента. Това позволява от range() да се получи всякаква целочослена редица, започваща от кое да е число.

for i in range(12, 16):
    print(i)

Първият аргумент ще е началната стойност на променливата на for цикъла. Втората променлива е границата, при която цикълът ще спре да се изпълнява.

12
13
14
15

Функцията range() може да се извика и с три аргумента. Първите два аргумента са началната и граничната стойност. Третият ще е стъпката. След всяко завъртане на цикъла променливата се увеличава със стойността на стъпката.

for i in range(0, 10, 2):
    print(i)

Извикването range(0, 10, 2) ще преброи от нула до осем, с разлика между поредните числа, равна на две.

0
2
4
6
8

Функцията range() е много гъвкава при използването ѝ за получаване на редици от числа. Например може да се използва отрицателно число за стъпка, за получаване на намаляваща редица :

for i in range(5, -1, -1):
    print(i)

Този for цикъл ще има следния резултат :

5
4
3
2
1
0

Използване на модули

Всички Python програми могат да извикват базов набор от функции, наречени вградени функции (built-in functions). Те включват вече използваните функции print(), input() и len(). Python има и набор от модули, наречен стандартна библиотека (standard library). Всеки модул е програма, която съдържа групирани функции, които могат да се използват в други програми. Модулът math съдържа математически функции, модулът random съдържа функции за случайни числа и т.н.

Даден модул трябва да се импортира, за да се използва функциите от този модул. Импортирането на модул се прави с import израз. В кода той се състои от следното :

  • Запазената дума import
  • Името на модула
  • Евентуално още имена на модули, разделени със запетаи

След импортиране на модула могат да се използват всичките негови функции. Следва пример с модула random, който предоставя функцията random.randint(). Кода на програмата printRandom.py :

import random
for i in range(5):
    print(random.randint(1,10))

При изпълението на програмата се получава резултат, подобен на :

3
8
3
10
2

Извикването на функцията random.randint() се пресмята до случайно цяло число, в интервала на двете числа, които се подават на функцията. Функцията randint() е от модула random, така че трябва да се напише първо random. преди името ѝ. Така Python знае, че тази фукнция трябва да се потърси в модула random.

Ето пример за израз import, който импортира четири различни модула :

import random, sys, os, math

След този ред могат да се използват всички функции от тези четири модула.

Израз from import

Алтернативна форма на изразът import се състои от запазената дума from, последвана от името на модул, запазената дума import и звезда. Пример за подобен израз е from random import *.

При тази форма на import няма нужда от добавяне на random. при извикване на фукнция от random. Все пак използването на пълната форма прави кода по-четим, така че е по-добре да се използва формата import random.

Преждевременно приключване на програма с функцията sys.exit()

Последната концепция от управлението на изпълнението е прекратяването на програмата. Програмите винаги приключват след изпълнението на последната инструкция. Обаче програмата може да се прекрати принудително преди последната инструкция, с извикване на функцията sys.exit(). Тази функция се намира в модула sys, който трябва да се импортира, преди да се използва в програма.

Следва примерна програма, записана като exitExample.py :

import sys
while True:
    print('Въведи изход за изход.')
    response = input()
    if response == 'изход':
        sys.exit()
    print('Въведе ' + response + '.')

Тази програма има безкраен цикъл без break израз. Единственият начин за приключване на програмата е с изпълнение на извикването на sys.exit(). Редът с sys.exit() ще се изпълни, ако променливата response е равна на изход. Стойността на променливата response се присвоява на функцията input(), така че потребителят трябва да въведе изход, за да спре програмата.

Кратка програма : Познай числото

Примерите до сега са полезни за въведение в основните идеи, но сега следва завършена програма, в която са комбинирани. Тя представлява проста игра "познай числото". При стартиране на програмата се получава подобен резултат :

Намислих число между 1 и 20
Предположи число:
10
Пробвай надолу.
Предположи число:
5
Пробвай нагоре.
Предположи число:
7
Пробвай нагоре.
Предположи число:
8
Браво! Позна числото с 4 опита

Ето и кода на програмата, guessTheNumber.py:

# Това е игра "познай числото"
import random
secretNumber = random.randint(1, 20)
print('Намислих число между 1 и 20')


# Играчът има право на 6 опита
for guessesTaken in range(1, 7):
    print('Предположи число:')
    guess = int(input())


    if guess < secretNumber:
        print('Пробвай нагоре.')
    elif guess > secretNumber:
        print('Пробвай надолу.')
    else:
        break # Правилно предположение


if guess == secretNumber:
    print('Браво! Позна числото с ' + str(guessesTaken) + ' опита')
else:
    print('Не позна. Бях си намислил ' + str(secretNumber))

Следва анализ на всеки ред род, започвайки от първия.

# Това е игра "познай числото"
import random
secretNumber = random.randint(1, 20)

Първо, коментар в началото, който обяснява какво прави програмата. След това се импортира модула random, от който се използва функцията random.randint() за генериране на число, което трябва да се отгатне. Резултатът от извикването на функцията, който е случайно цяло число между 1 и 20, се записва в променливата secretNumber.

print('Намислих число между 1 и 20')


# Играчът има право на 6 опита
for guessesTaken in range(1, 7):
    print('Предположи число:')
    guess = int(input())

Програмата уведомява играча, че е намислила число и ще му даде право на шест опита да го познае. Кодът, който позволява на играча да опита да познае и прави проверка, е в тялото на for цикъл, който ще се изпълни най-много шест пъти. Първото нещо, което става в тялото на цикъла, е въвеждане на предположение от играча. Функцията input() връща низ, така че върнатата стойност се подава на int(), която преобразува низ в целочислена стойност. Тази стойност се записва в променливата guess.

    if guess < secretNumber:
        print('Пробвай нагоре.')
    elif guess > secretNumber:
        print('Пробвай надолу.')

Тези няколко реда код проверяват дали предположението е по-малко или по-голямо от намисленото число. И в двата случая на екрана се показва подсказка.

    else:
        break # Правилно предположение

Ако предположението не е нито по-високо, нито по-ниско, от намисленото число, значи трябва да е равно на него. В този случай трябва изпълнението на програмата да излезе от for цикъла.

if guess == secretNumber:
    print('Браво! Позна числото с ' + str(guessesTaken) + ' опита')
else:
    print('Не позна. Бях си намислил ' + str(secretNumber))

След for цикъла следва if..else конструкция, която проверява дали играчът е познал числото и показва съответното съобщение. И в двата случая в съобщението се използва числена стойност (guessesTaken или secretNumber). За слепването на числа и низ се използва функцията str(), която връща низовата стойност на подаденото яисло. След това тези стрингове могат да се слепят с използване на оператора +, за да се подаде при извикването на функцията print().

Кратка програма : Камък, Ножица, Хартия

Следва проста програма за игра на "Камък, ножица, хартия", в която отново се демонстрират показаните до тук програмни конструкции. Играта изглежда по следния начин :

КАМЪК, НОЖИЦА, ХАРТИЯ
0 Победи, 0 Загуби, 0 Равни
Въведи ход : (к)амък (н)ожица (х)артия или (и)зход
х
ХАРТИЯ срещу ...
ХАРТИЯ
Равенство!
0 Победи, 0 Загуби, 1 Равни
Въведи ход : (к)амък (н)ожица (х)артия или (и)зход
н
НОЖИЦА срещу ...
ХАРТИЯ
Печелиш!
1 Победи, 0 Загуби, 1 Равни
Въведи ход : (к)амък (н)ожица (х)артия или (и)зход
и

Ето и кодът на програмата, записан като rpsGame.py:

import random, sys

print('КАМЪК, НОЖИЦА, ХАРТИЯ')

# Тези променливи броят победите, загубите и равенствата
wins = 0
losses = 0
ties = 0

while True: # Основният цикъл на играта
    print('%s Победи, %s Загуби, %s Равни' % (wins, losses, ties))
    while True: # Цикъл за избор на ход от играча
        print('Въведи ход : (к)амък (н)ожица (х)артия или (и)зход')
        playerMove = input()
        if playerMove == 'и':
            sys.exit() # Приключване на програмата
        if playerMove == 'к' or playerMove == 'н' or playerMove == 'х':
            break # излизане от цикъла за избор на ход
        print('Въведи една буква: к, н, х или и')

    # Показва изборът на играча
    if playerMove == 'к':
        print('КАМЪК срещу ...')
    elif playerMove == 'н':
        print('НОЖИЦА срещу ...')
    elif playerMove == 'х':
        print('ХАРТИЯ срещу ...')

    # Избор на компютъра
    randomNumber = random.randint(1, 3)
    if randomNumber == 1:
        computerMove = 'к'
        print('КАМЪК')
    elif randomNumber == 2:
        computerMove = 'н'
        print('НОЖИЦА')
    elif randomNumber == 3:
        computerMove = 'х'
        print('ХАРТИЯ')

    # Пресмятане и записване на резултата
    if playerMove == computerMove:
        print('Равенство!')
        ties = ties + 1
    elif playerMove == 'к' and computerMove == 'н':
        print('Печелиш!')
        wins = wins + 1
    elif playerMove == 'х' and computerMove == 'к':
        print('Печелиш!')
        wins = wins + 1
    elif playerMove == 'н' and computerMove == 'х':
        print('Печелиш!')
        wins = wins + 1
    elif playerMove == 'к' and computerMove == 'х':
        print('Губиш!')
        losses = losses + 1
    elif playerMove == 'х' and computerMove == 'н':
        print('Губиш!')
        losses = losses + 1
    elif playerMove == 'н' and computerMove == 'к':
        print('Губиш!')
        losses = losses + 1

Следва кратък анализ на програмата.

import random, sys

print('КАМЪК, НОЖИЦА, ХАРТИЯ')

# Тези променливи броят победите, загубите и равенствата
wins = 0
losses = 0
ties = 0

Първо се импортират модулите random и sys, от които ще се използват функциите random.randint() и sys.exit(). Също така се зануляват три променливи, в които ще се пазят броят на победите, загубите и равенствата на играча.

while True: # Основният цикъл на играта
    print('%s Победи, %s Загуби, %s Равни' % (wins, losses, ties))
    while True: # Цикъл за избор на ход от играча
        print('Въведи ход : (к)амък (н)ожица (х)артия или (и)зход')
        playerMove = input()
        if playerMove == 'и':
            sys.exit() # Приключване на програмата
        if playerMove == 'к' or playerMove == 'н' or playerMove == 'х':
            break # излизане от цикъла за избор на ход
        print('Въведи една буква: к, н, х или и')

Тази програма използва while цикъл, вложен в друг while цикъл. Първият цикъл е основният, всяко негово завъртане е една игра на камък, ножица, хартия. Вторият цикъл приема ход от играча и се върти, докато играчът не въведе к, н, х или и. Ход к, н и х съответства на избор на камък, ножица или хартия, а и означава изход. При изборане на изход се извиква sys.exit() за прекратяване на програмата. Изпълнението на програмата излиза извън втория цикъл при избор на играча к, н или х. При всеки друг избор се показва напомняне на позволенните ходове и следва ново завъртане на цикъла.

    # Показва изборът на играча
    if playerMove == 'к':
        print('КАМЪК срещу ...')
    elif playerMove == 'н':
        print('НОЖИЦА срещу ...')
    elif playerMove == 'х':
        print('ХАРТИЯ срещу ...')

На екрана се показва избраният от играча ход.

    # Избор на компютъра
    randomNumber = random.randint(1, 3)
    if randomNumber == 1:
        computerMove = 'к'
        print('КАМЪК')
    elif randomNumber == 2:
        computerMove = 'н'
        print('НОЖИЦА')
    elif randomNumber == 3:
        computerMove = 'х'
        print('ХАРТИЯ')

След това се избира случаен ход, който да бъде изигран от компютъра. Извикването random.randint(1, 3) ще върне случайно число в интервала 1-3. Тази стойност (която ще е целочислена 1, 2 или 3) се записва в променливата randomNumber. Спрямо стойността на randomNumber програмата записва 'к', 'н' или 'х' в променливата computerMove. Също така се показва "изборът" на компютъра.

    # Пресмятане и записване на резултата
    if playerMove == computerMove:
        print('Равенство!')
        ties = ties + 1
    elif playerMove == 'к' and computerMove == 'н':
        print('Печелиш!')
        wins = wins + 1
    elif playerMove == 'х' and computerMove == 'к':
        print('Печелиш!')
        wins = wins + 1
    elif playerMove == 'н' and computerMove == 'х':
        print('Печелиш!')
        wins = wins + 1
    elif playerMove == 'к' and computerMove == 'х':
        print('Губиш!')
        losses = losses + 1
    elif playerMove == 'х' and computerMove == 'н':
        print('Губиш!')
        losses = losses + 1
    elif playerMove == 'н' and computerMove == 'к':
        print('Губиш!')
        losses = losses + 1

Накрая програмата сравнява низовете в playerMove и computerMove и показва резултата. Също така се увеличава стойността на някоя от променливите wins, losses или ties, спрямо резултатът от текущия рунд. След достигане до края на тялото на цикъла изпълнението на програмата се връща в началото на основния цикъл, с което се започва още една рунд.

Обобщение

Условията (изрази, които се пресмятат до True или False) позволяват да се създават програми, които вземат решения кой код да изпълнят или не. С помощта на цикли може даден код да се изпълнява многократно, доакто условието е изпълнено. Изразите break и continue са полезни при нужда от прекратяване на цикъл или прескачане до началото му.

С тези конструкции позволяват писането на по-интелигентни програми. В следващата глава се разглеждат функциите, които представляват друг начин за управляване на изпълнението.

Упражнения

  1. Кои са двете стойности на булевия тип данни? Как се пишат в кода?
  2. Кои са трите булеви оператора?
  3. Напишете таблиците на истинността за всеки булев оператор (тоест всяка комбинация от булеви стойности за оператора и какъв е резултатът).
  4. До какво се пресмятат следващите изрази?

    (5 < 4) and (3 == 5)
    not (5 > 4)
    (5 > 4) or (3 == 5)
    not ((5 > 4) or (3 == 5))
    (True and True) and (True == False)
    (not False) or (not True)

  5. Кои са шестте оператора за сравнение?
  6. Каква е разликата между оператора за равенство и оператора за присвояване на стойност ?
  7. Какво е условие и за какво се използва ?
  8. Кои са трите блока в следния код ?

    spam = 0
    if spam == 10:
        print('eggs')
        if spam > 5:
            print('bacon')
        else:
            print('ham')
        print('spam')
    print('spam')

  9. Напишете код, който изписва Здравей, ако променливата spam има стойност 1; показва Как си ?, ако стойността на spam е 2; и Поздрави в останалите случаи.
  10. С натискане на кои клавиши може да се прекъсне безкраен цикъл ?
  11. Каква е разликата между break и continue ?
  12. Каква е разликата между използването на range(10), range(0, 10) и range(0, 10, 1) в цикъл for ?
  13. Напишете кратка програма, която принтира числата от 1 до 10 с използване на for цикъл. След това напишете програмата с използване на while цикъл.
  14. Как би се извикала функция bacon() от модул spam ?
  15. Бонус задача: Потърсете функциите round() и abs() в интернет. Какво правят те?

Подкрепете автора чрез покупка на оригиналната книга от No Starch Press или Amazon.