Материалы по курсу «Основы программирования»

Лекция 5. «Анализ решений задач»

Возврат логических значений

Пример. Напишем функцию, которая определяет, являются ли три числа сторонами треугольника. Функцию назовём is_triangle(a, b, c)

def is_triangle(a, b, c):
    if a+b>c and b+c>a and c+a>b:
        return True
    else:
        return False

Это решение правильное, но его можно упростить. Рассмотрим выражение внутри if:

a+b>c and b+c>a and c+a>b

Значением этого выражения может быть либо True, либо False. Т.е. если, например, мы присвоим это выражение переменной, то в ней будет лежать или True, или False.

def is_triangle(a, b, c):
    res = a+b>c and b+c>a and c+a>b

    # в переменной res будет или True, или False

    if res:
        return True
    else:
        return False

Что мы сделали — значение выражения положили в переменную, внутрь if положили переменную. Это эквивалентное преобразование. Рассмотрим теперь условный оператор:

    if res:
        return True
    else:
        return False

Когда в переменной res лежит True, будет выполнена первая ветка if, т.е. выполнен оператор return True. Когда в переменной res лежит False, будет выполнена вторая ветка — оператор return False.

Всю вот эту конструкцию можно заменить эквивалентной:

    return res

Действительно, когда в res лежит True, выполнится return True, а когда лежит False — return False.

Значит, функцию можно упростить таким образом:

def is_triangle(a, b, c):
    res = a+b>c and b+c>a and c+a>b

    # в переменной res будет или True, или False

    return res

Переменная res используется один раз в return, значит её можно заменить на выражение, ей присвоенное:

def is_triangle(a, b, c):
    return a+b>c and b+c>a and c+a>b

Отличия print и return

Ранее мы писали два вида функций: функции, которые печатали требуемые значения при помощи print, и функции, которые возвращали значения при помощи return.

Пример. Функции hypot1(a, b) и hypot2(a, b), которые вычисляют гипотенузу прямоугольного треугольника:

def hypot1(a, b):
    c = (a**2 + b**2)**0.5
    print(с)

def hypot2(a, b):
    c = (a**2 + b**2)**0.5
    return c

Выглядят они похоже. Первая функция печатает значение при помощи вызова функции print, результат печатается в консоль. Вторая функция возвращает значение при помощи оператора return.

Если попытаемся их вызвать, то, на первый взгляд, отличий не увидим:

= RESTART: D:/temp/Коновалов/hypot.py
>>> hypot1(5, 12)
13.0
>>> hypot2(5, 12)
13.0
>>> 

В обоих случаях на консоль напечаталось значение гипотенузы. Но механизм печати разный. Попробуем найти отличие.

>>> h1 = hypot1(5, 12)
13.0
>>> print(h1)
None
>>> h2 = hypot2(5, 12)
>>> print(h2)
13.0
>>> 

Переменным h1 и h2 были присвоены значения, которые эти две функции возвращают. Функция hypot1 явным образом ничего не возвращает, т.к. в ней отсутсвует оператор return. Если оператор return отсуствует, то в конце функции неявно подразумевается оператор return None. Т.е. функция hypot1 неявно выглядит так:

def hypot1(a, b):
    c = (a**2 + b**2)**0.5
    print(c)
    return None

Функция hypot1(a, b) что делает:

  1. Вычисляет гипотенузу, кладёт её в переменную c.
  2. Вызывает функцию print(c), которая печатает значение c в консоли.
  3. Завершает свою работу с возвратом значения None.

Среда IDLE после вычисления выражения hypot1(5, 12) видит, что результат выражения — None и его не печатает. Поэтому мы видим только результат печати функции print:

>>> hypot1(5, 12)
13.0

Вообще, среда IDLE в консоли никогда не печатает None:

>>> None
>>> x = None
>>> x
>>> 

Среда IDLE тут не распечатала None ни когда мы его явно ввели, ни когда мы попытались распечатать значение переменной x. Другие значения в этих случаях будут печататься:

>>> False
False
>>> y = False
>>> y
False
>>> 3.1415926
3.1415926
>>> pi = 3.1415926
>>> pi
3.1415926
>>> 

Значения False и 3.1415926, в отличие от None, печатаются как ожидалось.

Чтобы увидеть значение None в консоли, нужно его распечатать функцией print:

>>> print(None)
None
>>> print(x)
None
>>> print(h1)
None
>>> 

Поэтому в примере выше мы писали не

>>> h1

а

>>> print(h1)

Соответственно, в примере

>>> h1 = hypot1(5, 12)
13.0
>>> print(h1)
None

мы видим, функция hypot1 напечатала значение, а возвращаемое значение (т.е. результат вызова) — это None, лежит в переменной h1.

Функция hypot2(a, b) возвращает величину гипотенузы как свой результат:

def hypot2(a, b):
    c = (a**2 + b**2)**0.5
    return c

При вызове в консоли hypot2(5, 12):

  1. Функция hypot2 вычисляет гипотенузу по теореме Пифагора, кладёт её в переменную c.
  2. Возвращает значение переменной c как свой результат.
  3. Среда IDLE видит, значение выражения 13.0, т.е. оно не равно None, и его печатает.
>>> hypot2(5, 12)
13.0
>>> h2 = hypot2(5, 12)
>>> print(h2)
13.0

Во втором примере (с присваиванием) возвращаемое значение кладётся в переменную h2, а для присваиваний среда IDLE ничего не печатает. Вызов print(h2) просто распечатывает значение переменной.

Заметим, что функция print(…) тоже возвращает None:

>>> p = print('hello')
hello
>>> print(p)
None

Ещё пример:

def example():
    print("Это напечатает print")
    return "Это вернёт return"
    print("Это не напечатается")
============= RESTART: D:/temp/Коновалов/hypot.py ============
>>> example()
Это напечатает print
'Это вернёт return'
>>> 

Здесь функция сначала напечатала первую строку, потом вернула вторую. Среда IDLE увидела, что функция вернула не None, и напечатала результат работы функции (т.е. вторую строку). Возвращаемое значение печатается в машиночитаемой форме, т.е. для строк — в кавычках.

Третья строчка не напечаталась, т.к. return завершает выполнение функции. Вызов print — не завершает работу функции, это просто вызов другой функции.

Возвращаемое значение можно увидеть отдельно, если его присвоить переменной:

>>> z = example()
Это напечатает print
>>> z
'Это вернёт return'
>>> 

Возвращаемое значение было присвоено переменной z. В ответ на присваивание сама среда IDLE ничего не печатает, мы видим только то, что печатает функция при помощи print.

Возвращённое значение можно использовать в вычислениях:

>>> 7 + hypot2(5, 12)
20.0

Напечатанное значение уже использовать нельзя, его можно только смотреть глазами:

>>> 7 + hypot1(5, 12)
13.0
Traceback (most recent call last):
  File "<pyshell#70>", line 1, in <module>
    7 + hypot1(5, 12)
TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
>>> 

Вызов функции hypot1 напечатал 13.0, затем вернул None. Мы попытались сложить 7 (типа int) и None (типа NoneType) и получили это сообщение об ошибке: нельзя использовать + для int и NoneType.