02. Условные конструкции. Цикл while.


На предыдущем занятии мы узнали о таких типах данных как число и строка. Но существует еще один ключевой тип данных в языках программирования.

Тип данных bool

Изучим логический тип данных, в нем существуют всего два значения $-$ True (правда) и False (ложь).

In [1]:
True, False
Out[1]:
(True, False)

Если рассматривать эти значения в числовом контексте, то ведут они себя как целые 1 и 0 соответственно.

In [2]:
int(True), int(False)
Out[2]:
(1, 0)
In [3]:
True * True
Out[3]:
1
In [4]:
True + False + True
Out[4]:
2

Точно так же, как и для других типов данных, есть функция преобразования в тип bool(). Нулевые и пустые значения - False, Ненулевые и непустые значения - True:

In [5]:
bool(1), bool(20), bool('something'), bool(0), bool(''), bool()
Out[5]:
(True, True, True, False, False, False)

Операторы сравнения

Подробнее читать документацию

Мы можем сравнивать объекты и тем самым получать значение True/False

In [6]:
print('Is 10 > 3? ', 10 > 3)   # больше
print('Is 10 >= 3?', 10 >= 3)  # больше или равно
print('Is 4 < 5?  ', 4 < 5)    # меньше
print('Is 4 <= 5? ', 4 <= 5)   # меньше или равно
print('Is "abc" == "abc"?', 'abc' == 'abc')  # равняется
print('Is 1 == 10?       ', 1 == 10)
print('Is "cat" != "dog"?', 'cat' != 'dog')  # не равняется
Is 10 > 3?  True
Is 10 >= 3? True
Is 4 < 5?   True
Is 4 <= 5?  True
Is "abc" == "abc"? True
Is 1 == 10?        False
Is "cat" != "dog"? True

Операторы сравнения можно группировать скобками

In [7]:
(42 != 42) == 0
Out[7]:
True

и объединять в цепочки

Comparisons can be chained arbitrarily, e.g., x < y <= z is equivalent to x < y and y <= z, except that y is evaluated only once (but in both cases z is not evaluated at all when x < y is found to be false).

In [8]:
x = 42
3.14 < x <= 57, 42.0 == x == 42.0 > 57, (42.0 == x and x == 42.0 and 42 > 57)
Out[8]:
(True, False, False)

Логические функции

DOCS

Существуют также логические функции И, ИЛИ, НЕ

И обозначается союзом and (так же, если рассматривать булевые значения как числа 0 и 1, то И это операция умножения)

In [9]:
True and True, True and False, False and True, False and False
Out[9]:
(True, False, False, False)

ИЛИ обозначается союзом or (так же, если рассматривать булевые значения как числа 0 и 1, то ИЛИ это операция сложения)

In [10]:
True or True, True or False, False or True, False or False
Out[10]:
(True, True, True, False)

НЕ обозначается частицей not

In [11]:
not True, not False 
Out[11]:
(False, True)

Оператор is

Оператор is (и в сочетании с частицей is not) тестируют объекты (а не их значения) на идентичность: x is y верно тогда и только тогда, когда x и y это один итот же объект. Идентификатор объекта определяется функцией id(). Для коротких строк и чисел от -5 до 256, объекты с одинаковым значениям хранятся в одном и том же месте (поэтому id одинаковый). Например:

In [12]:
x = 256
y = 256
x is y, x == y, id(x), id(y),
Out[12]:
(True, True, 10922656, 10922656)
In [13]:
a = -5
b = -5
a is b, a == b, id(a), id(b),
Out[13]:
(True, True, 10914304, 10914304)
In [14]:
s1 = 'hello'
s2 = 'hello'
s1 is s2, s1 == s2, id(s2), id(s2)
Out[14]:
(True, True, 140279810460896, 140279810460896)
In [15]:
x = 257
y = 257
x is y, x == y, id(x), id(y)
Out[15]:
(False, True, 140279810734160, 140279810734192)
In [16]:
a = -6
b = -6
a is b, a == b, id(a), id(b)
Out[16]:
(False, True, 140279810734352, 140279810734000)
In [17]:
s1 = 'hello world'
s2 = 'hello world'
s1 is s2, s1 == s2, id(s2), id(s2)
Out[17]:
(False, True, 140279810718704, 140279810718704)

Объект None

Существует также объект None, который должен существовать как и в реальном мире (хотя вопрос философский). Он обозначает ничего и не имеет поведения. Он как объект имеет тип NoneType, однако обратите внимание, что с классом NoneType вам работать не придется, по большому счету вы работаете только с единственным значением, которое представляет собой объект None:

In [18]:
type(None), None
Out[18]:
(NoneType, None)

Если перевести None в булевый тип, то он всегда будет False, поэтому можно его использовать в условных конструкциях и пр.:

In [19]:
bool(None)
Out[19]:
False

В решении задач None может использоваться для подчеркивания "ничего", а еще позже, когда мы дойдем до созданиия своих классов и numpy. Например:

In [20]:
import random

revenue = None
time = 9

if random.uniform(0, 1) > 0.5: # с какой-то вероятностью работник пошел на работу
    revenue = 0
    while time < 18:
        revenue += random.uniform(0, 150) # и зарабатывает от 0 до 150 рублей в час
        time += 1
        if time == 14:
            revenue -= random.uniform(100, 600) # и обедает на какую-то сумму

if revenue is None: # if not revenue:
    print('Мы не вышли на работу!')
elif revenue < 0:
    print('Мы ушли в минус из-за обеда:', revenue, 'рублей')
elif revenue < 300:
    print('Мы заработали меньше денег, чем нужно:', revenue, 'рублей')
else:
    print('Мы заработали достаточно:', revenue, 'рублей')
Мы не вышли на работу!

Обратите внимание, как мы использовали оператор is вместо ==. В целом, можно использовать оба варианта, они будут работать. Но общепринято использовать именно is, так как он будет работать в любом случае.

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

До этого строчки кода исполнялись просто друг за другом, но что если хочется выполнять разные действия в зависимости от какого-то условия? Тогда на помощь приходят условные конструкции. Вот пример:

In [21]:
number = int(input('Введите число ---> '))
if number > 0:
    print('Введено положительное число')
elif number < 0:
    print('Введено отрицательно число')
else:
    print('Введен ноль!')
Введите число ---> 42
Введено положительное число

То есть конструкция такая:

if (Условие 1):
    Блок инструкций 1
elif (Условие 2):
    Блок инструкций 2
else:
    Блок инструкций ИНАЧЕ

Программа проверяет условия по очереди сверху вних и если одно из них выполнилось, то выполняет его блок инструкций, после чего продолжает исполнять код, который идет после всей конструкции if-else. Если ни одно из условий не выполнилось и есть часть else, то выполняется ее блок инструкций.

Средняя часть elif может быть в любом количестве или даже не быть! Например:

In [22]:
number = int(input('Введите число ---> '))

if number != 0:
    print('Введен не ноль!')
else:
    print('Введен ноль!')
Введите число ---> 42
Введен не ноль!
In [23]:
number = int(input('Введите число ---> '))

if number == 0:
    print('Введен ноль!')
elif number == 1:
    print('Введена единица!')
elif number == 2:
    print('Введена двойка!')
elif number == 7:
    print('Введена семерка!')
elif number == 42:
    print('Введен ответ на все вопросы...')
else:
    print('Введено какое-то число.. Хм.')
Введите число ---> 42
Введен ответ на все вопросы...

На самом деле и части else может не быть. Если условие не выполнилось, то просто код продолжит работу дальше.

In [24]:
number = int(input('Введите число ---> '))

if number == 0:
    print('Введен ноль!')
print('---')
Введите число ---> 42
---

Такие конструкции могут быть вложены друг в друга:

In [25]:
number = int(input('Введите число ---> '))

if number > 0:
    if number < 100: # слева стоит 4 пробела!
        print('Введено небольшое положительное число')
    else:
        print('Введено большое положительное число')
else:
    print('Введено неположительное число')
Введите число ---> 42
Введено небольшое положительное число

Важно заметить, что условие это просто какое-то верное или ложное утверждение (то есть bool переменная True или False). Как мы уже изучили, можно строить сложные логические утверждения, которые так же принимают эти значения. Значит их тоже можно ставить как условия:

In [26]:
number = int(input('Введите число ---> '))

if (number % 2 == 0) and (number > 0):
    print('Введено положительное четное число!')
else:
    print('Введен отрицательное или нечетное число!')
Введите число ---> 42
Введено положительное четное число!

Вспомним, что числа тоже можно представить как bool значение, а значит и использовать как условия!

In [27]:
number = int(input('Введите число ---> '))

if (number % 2): # остаток от деления на два равен 0 (четное) или 1 (нечетное)
    print('Введено нечетное число!')
else:
    print('Введен четное число!')
Введите число ---> 42
Введен четное число!

Задача 1

Дано натуральное число. Требуется определить, является ли год с данным номером високосным. Если год является високосным, то выведите "Високосный год", иначе выведите "Не високосный год".

Напомним, что год является високосным, если его номер кратен 4, но не кратен 100, а также если он кратен 400.

Задача 2

Вводятся два числа a и b. Выведите какое число было больше и его значение. Если числа равны, выведите "Числа равны" и значение.

Цикл while

Что такое цикл? Повторяющийся набор действий в течение какого-то заданного времени (количество итераций или выполнение условия).

Цикл while ("пока") выполняется, пока какое-то заданное условие является Истинным:

In [28]:
i = 10
while i > 0:
    print(i, end='->')
    i -= 1
    print(i)
print('end')
10->9
9->8
8->7
7->6
6->5
5->4
4->3
3->2
2->1
1->0
end

Конструкция простая:

while Условие(зависимое от X):
    Блок кода, меняющий Х

Такой цикл легко может стать бесконечным (что, как правило, плохо и является ошибкой), если внутри блока кода не менять никак значения, которые влияют на условие.

In [ ]:
i = 10
while i > 0:
    print(i, end=' ')

Прерывание работы цикла break

DOCS

Если во время исполнения цикла внутри блока кода встретится команда break, то "исполнитель" выйдет из цикла совсем.

In [30]:
i = 10
k = 1.5
while i > 0:
    print('i =', i,'\tk =', k)
    if k > 15:
        break
    i += 1
    k *= k
i = 10 	k = 1.5
i = 11 	k = 2.25
i = 12 	k = 5.0625
i = 13 	k = 25.62890625

Пропуск цикла continue

Если во время исполнения цикла внутри блока кода встретится команда continue, то "исполнитель" пропустит весь код ниже команды внутри блока кода и перейдет к следующей итерации (loop, цикл)

In [31]:
i = 0
 
while i < 10:
    if not (i % 3):
        i += 1
        continue # не будет принта
    print(i, end=' ')   
    i += 1
1 2 4 5 7 8 

Волшебное слово else

Слово else, примененное в цикле for или while, проверяет, был ли произведен выход из цикла инструкцией break, или же "естественным" образом. Блок инструкций внутри else выполнится только в том случае, если выход из цикла произошел без помощи break.

In [32]:
i = -1
while i < 2:
    if i == 2:
        print('Разрыв цикла')
        break
    i += 1
else:
     print('Естественный конец цикла')
Естественный конец цикла

Как делать не стоит

In [33]:
i = 0
while True: # нечитаемое условие окончания цикла, можно наделать ошибок
    print(i, end=' ')
    i += 2
    if i == 10:
        break        
0 2 4 6 8 

Задача 3.1

Даны два целых числа A и B (при этом A ≤ B). Выведите все числа от A до B включительно.

Задача 3.2

Даны два целых числа A и В. Выведите все числа от A до B включительно, в порядке возрастания, если A < B, или в порядке убывания в противном случае.

Задача 4

По данному натуральному числу N найдите наибольшую целую степень двойки, не превосходящую N. Выведите показатель степени и саму степень.