Занятие № 10. Описание функций пользователя

Цель: научиться применять функции для решения задач и структурирования кода программы.

Теория

Определение функции

Функция – это именованный набор инструкций, которые могут быть выполнены в любом месте программы, после вызова функции.

Для объявление функции используется инструкция def. Инструкция def создаёт новый объект-функцию:

def <имя функции>(<параметры>):
    <блок инструкций>

Строка с инструкцией def называется заголовком функции, а блок инструкций внутри функции называется телом функции. Имя функции следует правилам именования переменных в Python.

Вот пример объявления функции с именем hello, которая выведет на экран два сообщения:

def hello():
    """Это функция приветствует пользователя"""
    print("Привет")
    print("Рад видеть вас")

      
def hello():
    """Это функция приветствует пользователя"""
    print("Привет")
    print("Рад видеть вас")

Если запустить код выше, то мы не увидим сообщений на экране. Нужно разделять определение функции и её вызов.

Вызов функции

Чтобы вызвать функцию нужно записать её имя и в круглых скобках указать аргументы, если необходимо:

<имя функции>(<аргументы>)

Например чтобы вызвать функцию hello мы запишем следующее: x hello().

Проследите за вызовом функции hello по шагам.

На втором шаге за именем hello закрепляется объект типа function. Это и будет объект, которых хранит описание функции. На шестом шаге мы вызываем функции hello. После этого начнут выполняться инструкции в теле функции. Когда инструкции закончатся, управление вернётся основной программе. В итого в этом примере мы вызываем функцию hello x раза.

Сколько строк будет содержать результат работы следующей программы:

def result():
    print("Хорошего дня!")
    print("Успехов в работе")

Верно. В коде есть только объявление функции, но нет вызова. Этот код ничего не выведет на экран. Чтобы получить сообщения, нужно записать следующее:

def result():
    print("Хорошего дня!")
    print("Успехов в работе")
    
result() # вызов функции

В определении функции не одна функция print().

Когда мы вызовем функцию result() на экране появятся две строки с текстом. Но в этом коде нет вызова функции.

Параметры и аргументы

Параметры функции - это входные данные, на основе которых функция должна получить требуемый результат. Параметры перечисляются в заголовке определения функции через запятую. В следующем примере функция hello2 принимает два параметра - имя name и количество повторений rep:

def hello2(name, rep):
    msg = " Привет, " + name
    print(msg * rep)

При вызове такой функции мы должны указать необходимые аргументы - буквальные значения или выражения, которые сопоставляются с параметрами в определении функции. Если мы запишем hello2("Света", 3), значит параметр name примет строковое значение "Света", а параметр rep будет иметь значение равное числу x :

def hello2(name, rep):
    msg = " Привет, " + name
    print(msg * rep)
    
hello2("Света", 3)
hello2("Дима", 4)

      
def hello2(name, rep):
    msg = " Привет, " + name
    print(msg * rep)
    
hello2("Света", 3)
hello2("Дима", 4)

Неизменяемые объекты передаются по значению (числа, строки) и не могут быть изменены в теле функции. Изменяемые объекты передаются по ссылке (списки, словари) и могут быть изменены в теле функции.

 

В каком из предложенных вариантов заголовок функции записан корректно:


Верно.

Не хватает () после имени функции. Они ставятся в заголовке даже если функция не принимает параметры.

Не хватает служебного слова def.

Заголовок описания функции должен оканчиваться :. Со следующей строки с отступа начинается блок инструкций - тело функции.

Какие параметры есть в объявлении следующей функции:

def print_many(x, y):
    """Печатает строку x, y раз"""
    for i in range(y):
        print(x)

Верно, у этой функции два параметра.

Переменная i используется в теле функции но не в качестве входного параметра.

Это только один из параметров функции.

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

Глядя на следующий код, выберите вариант инструкции с помощью которой можно вызвать объявленную функцию:

def print_many(x, y):
   """Печатает строку x, y раз"""
   for i in range(y):
       print(x)

z = 3

Верно. Переменная z имеет значение, равное 3. Первым аргументом мы передали строку "Привет".

x и y - имена параметров функции. При вызове функции вместо параметров указываются реальные значения или выражения.

При вызове функции всегда нужны круглые скобки, даже если в объявлении функции нет параметров.

Эта функция принимает два аргумента, а в этом варианте указан только один.

Во время вызова функции двоеточие в конце не ставится. Оно необходимо только при объявлении функции. Возникнет ошибка.

Что выведет на экран следующая программа:

def lng(s1, s2):
   if len(s1) > len(s2):
      print(s1)
   else:
      print(s2)

lng("Привет", "Пока")

Верно. Функция lng() выведет на экран наибольшую по длине строку.

Функция lng() выводит на экран наибольшую по длине строку.

s1 - это имя переменной. Программа выведет значение на которое ссылается переменная.

s2 - это имя переменной. Программа выведет значение на которое ссылается переменная.

Параметры и аргументы в Python могут сопоставляться несколькими способами. При сопоставлении по позиции важен порядок в котором аргументы записаны при вызове функции:

def formatDate(day, month, year):
    """Выводим дату в красивом формате"""
    print(f"Сегодня {day}.{month} {year} года")

formatDate(22, 11, 2024) # аргументы в правильном порядке
formatDate(11, 2024, 22) # аргументы перепутаны

      
def formatDate(day, month, year):
    """Выводим дату в красивом формате"""
    print(f"Сегодня {day}.{month} {year} года")

formatDate(22, 11, 2024) # аргументы в правильном порядке
formatDate(11, 2024, 22) # аргументы перепутаны

Сопоставление по имени позволяет записывать аргументы в произвольном порядке но нужно указать имена параметров из заголовка функции:

def formatDate(day, month, year):
    print(f"Сегодня {day}.{month} {year} года")

# аргументы в произвольном порядке
formatDate(month=11, year=2024, day=22) 

      
def formatDate(day, month, year):
    print(f"Сегодня {day}.{month} {year} года")

# аргументы в произвольном порядке
formatDate(month=11, year=2024, day=22) 

В объявлении функции можно указать значения по умолчанию для параметров:

def formatDate(day, month, year=2024):
    print(f"Сегодня {day}.{month} {year} года")

formatDate(1, 9)
formatDate(1, 9, 1991)

      
def formatDate(day, month, year=2024):
    print(f"Сегодня {day}.{month} {year} года")

formatDate(1, 9)
formatDate(1, 9, 1991)

Так как при вызове функции formatDate(1, 9) не указано значение параметра year, при выполнении функции будет использовано значение по умолчанию равное x ? .

Возвращаем значение - return

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

graph LR
    str(["&quot;банан&quot;"])-.->|аргумент|len[["len()"]]
    len-.->|return|res([5])
Рисунок 1

На вход функция принимает последовательность и возвращает количество элементов в ней.

Чтобы вернуть значение из функции используется инструкция return.

В следующем примере опишем функцию square(x), которая возводит число в квадрат:

def square(x):
    y = x * x
    return y  # возвращаем результат из функции

n = 10
result = square(n)
print("Результат:", result)

      
def square(x):
    y = x * x
    return y  # возвращаем результат из функции

n = 10
result = square(n)
print("Результат:", result)

После return записывается выражение, результат которого вычисляется и возвращается в то выражение, откуда была вызвана функция. В коде выше функция square() вызывается в x строке.

Если в определении функции нет инструкции return то по окончании работы она всё равно вернёт специальное значение None:

def square(x):
    y = x * x
    # забыли написать return

print("Результат:", square(8))

      
def square(x):
    y = x * x
    # забыли написать return

print("Результат:", square(8))

После выполнения инструкции return функция прекращает свою работу. Если какие-либо инструкции были записаны после return, они выполняться не будут:

def year():
    print("Функция запустилась")
    return 2024
    print("Это строка не выполнится")
    return 2007 # эта тоже

x = year()
print(x)

      
def year():
    print("Функция запустилась")
    return 2024
    print("Это строка не выполнится")
    return 2007 # эта тоже

x = year()
print(x)

Но стоит понимать, что в функции может быть несколько инструкций return:

def year(val):
    if val == 2024:
        return "Текущий год"
    elif val < 2024:
        return "Прошлый год"
    else:
        return "Будущее"

x = year(1991)
print(x)

      
def year(val):
    if val == 2024:
        return "Текущий год"
    elif val < 2024:
        return "Прошлый год"
    else:
        return "Будущее"

x = year(1991)
print(x)

Если в примере выше вызвать функцию year(2077), то она вернёт строку x "Будущее".

 

Что не так в определении данной функции:

def addEm(x, y, z):
    return x+y+z
    print('Ответ', x+y+z)

Верно. После инструкции return функцию возвращает значение и завершает работу.

Функция print() может встречаться в теле функции. Главное не путать её вызов с возвратом значения.

Делать это не обязательно. Python сам вычислит значение выражения и вернёт его. Но с помощью временной переменно будет проще отладить программу в случае ошибки.

Функция может возвращать данные любого типа.

Что будет выведено на экран после выполнения следующего кода:

def square(x):
    y = x * x
    return y

print(square(square(2)))

Верно. Выражение square(2) будет равно 4. Затем четвёрка будет аргументом для внешнего вызова функции square(4).

Результат работы функции square() - число. Этот результат мы можем передать в качестве аргумента в функцию. Выражение внутри print() можно записать через временную переменную так:

t = square(2)
print(square(t))
УведомлениеФункции - это объекты (щелкните, чтобы открыть)

Каждая функция в Python - это объект на который может ссылаться несколько имён, их можно сделать элементами списка или словаря.

def summa(a, b):
    return a + b

s = summa # теперь на функцию ссылаются два имени - summa и s
print(summa(3, 2))
print(s(3, 2))

      
def summa(a, b):
    return a + b

s = summa # теперь на функцию ссылаются два имени - summa и s
print(summa(3, 2))
print(s(3, 2))

В следующем примере три функции помещаем в список и перебираем этот список с помощью цикла for:

def summa(a, b):
    return a + b
def mult(a, b):
    return a * b
def power(a, b):
    return a ** b

func_lst = [summa, mult, power] # список функций

x = 4
y = 3
for func in func_lst:
    # на каждой итерации func ссылается на очередную функцию
    value = func(x, y)
    print(value)

      
def summa(a, b):
    return a + b
def mult(a, b):
    return a * b
def power(a, b):
    return a ** b

func_lst = [summa, mult, power] # список функций

x = 4
y = 3
for func in func_lst:
    # на каждой итерации func ссылается на очередную функцию
    value = func(x, y)
    print(value)

Перейдите по ссылке, если хотите проследить за пошаговым выполнение этой программы.

Примеры

Познакомьтесь с готовыми решениями задач. Ответьте на вопросы после кода решения задач.

Пример № 1 (ex01.py)

Объявите функцию progress(proc, symb), которая выводит на экран полоску прогресса выполнения задания: 0 % - пустая полоска, 100% - 10 повторяющихся символов. Функция принимает два параметра - процент выполнения задачи proc и символ для изображения прогресса её выполнения symb.

Аналогичный по назначению элемент можно увидеть, например, в окне копирования файлов и папок Windows:

Индикатор выполнения

Индикатор выполнения

Примеры работы программы:

Процент готовности: <{35}> ++enter++
###
Процент готовности: <{100}> ++enter++
##########

Объявление функции начинается с её заголовка. В нашей задаче заголовок функции будет выглядеть следующим образом: x def progress(proc, symb):.


Затем после отступа начинается тело функции. Параметр proc имеет значение от 0 до 100, но нам нужно получить от 0 до 10 символов symb. Применим целочисленное деление, которое выполняется оператором x //. Затем повторим символ вычисленное количество раз с помощью оператора x *.


Решение задачи выглядит следующим образом:

def progress(proc, symb):
    mult = proc // 10
    print(symb * mult)

ready = int(input("Процент готовности: ")) # ввод процента готовности
progress(ready, "#") # вызов процедуры

Запустите и протестируйте решение.

Добавим параметру symb в заголовке функции значение по умолчанию - "#". Заголовок изменится на следующий: x def progress(proc, symb="#"):.


Исправьте и дополните код решения:

def progress(proc, symb="#"): # [!] исправление
    mult = proc // 10
    print(symb * mult)

ready = int(input("Процент готовности: "))
progress(ready)         # [+] по умолчанию повторится символ "#"
progress(ready, "@")    # [+] теперь будет повторяться символ "@"
progress(ready, "$")    # [+] а тут - символ "$"

Пример работы программы:

Процент готовности: <{65}> ++enter++
######
@@@@@@
$$$$$$

Пример № 2 (ex02.py)

Напишите функцию total_cost(a, rho, cost) для вычисления стоимости изготовления детали кубической формы на 3D-принтере. Параметры функции - длина стороны куба a (м), плотность пластика rho (кг/м3), стоимость 1 кг пластика cost (руб).

Рассчитайте стоимость изготовления N таких деталей.

УведомлениеДля справки

Плотность PLA-пластика для 3D-печати - 1240 кг/м3. Стоимость 1 кг PLA-пластика - приблизительно 60 белорусских рублей.

Запишите и протестируйте код решения задачи:

def total_cost(a, rho=1240, cost=60):
    v = a ** 3
    res = v * rho / cost
    return res

N = int(input("Количество деталей: "))
d = float(input("Длина стороны куба (м): "))
print(total_cost(d) * N)

Пример работы программы:

Количество деталей: <{16}> ++enter++
Длина стороны куба (м): <{0.2}> ++enter++
2.6453333333333338

Пример № 3 (ex03.py)

Для функции, заданной графически, определить значение \(у\) при заданном значении \(х\).

Кусочно-заданная функция

Кусочно-заданная функция

\[ y(x) = \begin{cases} 1, & \text{если } x \le -1 \\ -x, & \text{если } -1 < x < 1 \\ -1, & \text{если } x \ge 1 \end{cases} \tag{1}\]

Запишите и протестируйте код решения задачи:

def f(x):
    if x <= -1:
        return 1
    elif x > -1 and x < 1:
        return -x
    else:
        return -1

print(f(-5))
print(f(0))
print(f(0.5))
print(f(2))

Пример работы программы:

1
0
-0.5
-1

Задания для самостоятельной работы

Решите следующие задачи самостоятельно.

Задание № 1 (sam01.py)

Опишите функцию sphere_volume(r) которая вычисляет и выводит на экран объём шара радиусом r. Для вычислений используйте следующую формулу: \[ V=\frac{4}{3}\pi r^3 \tag{2}\]

Пример работы программы:

V = 113.09733552923254
V = 0.9047786842338602

Составьте код решения из предложенных блоков. Внимание: среди них есть лишние.

import math
def sphere_volume(r):
    v = 4/3 * math.pi * r ** 3
    print(v)
sphere_volume(3)
sphere_volume(0.6)
print(v)
v = 4/3 * math.pi * r ** 3
v = 4/3 * pi * r ** 3
import math
def sphere_volume(r):
sphere_volume(3) sphere_volume(0.6)
return v
sphere_volume(r):

Наберите код решения в IDLE и протестируйте его.

Задание № 2 (sam02.py)

Напишите функцию build(r), которая рассчитает и вернёт количество кирпичиков Lego необходимых для строительства сферы радиусом r км. Размеры кирпичика фиксированные: 16 x 16 x 10 мм. Рассчитайте сколько кирпичиков Lego понадобится, чтобы построить планету с заданным радиусом.

Используйте следующий шаблон:

import math

# запишите тело функции вместо многоточия (...)
def build(r):
    ...
    return ... # укажите возвращаемое функцией значение или переменную


# не исправляйте данный код
earth = build(6371) # радиус Земли (км)
print(earth)

moon = build(1737) # радиус Луны (км)
print(moon)

Пример работы программы:

4.231277018928725e+26
8.575275849621095e+24

Сначала вычислите объём сферы по формуле 2, переведя радиус из км в мм.

Объём одного кирпичика: 16×16×10 мм3.

Верните из функции частное от деления объёма сферы на объём кирпичика (return).

Задание № 3 (sam03.py)

Опишите функцию create_email(msg, sub, sign), где msg - текст сообщения, sub - тема письма, sign - подпись автора письма. Тема письма, сообщение и подпись выводятся с новой строки.

В определении функции должны использоваться параметры по умолчанию:

  • если тема (sub) не указана, то используется строка Важное сообщение
  • если подпись (sign) не указана, то используется строка С уважением, друг

Используйте следующий шаблон:

# вместо этого комментария опишите необходимую функцию

# не исправляйте данный код
create_email("Завтра собрание")
print()
create_email("Сегодня тест", "Напоминание")
print()
create_email("Скоро сессия", "Привет", "Одногруппник")

Пример работы программы:

Тема: Важное сообщение
Завтра собрание
Подпись: С уважением, друг

Тема: Напоминание
Сегодня тест
Подпись: С уважением, друг

Тема: Привет
Скоро сессия
Подпись: Одногруппник

Задание № 4 (sam04.py)

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

Сравнение дробей

Сравнение дробей

Объявите функцию comp(ch1, zn1, ch2, zn2), которая возвращает символ с результатом сравнения дробей ch1 / zn1 и ch2 / zn2

Используйте следующий шаблон:

# вместо этого комментария опишите необходимую функцию


# не исправляйте данный код
print(comp(7, 10, 21, 30))
print(comp(7, 10, 5, 8))
print(comp(7, 10, 9, 12))

Пример работы программы:

=
>
<

Задание № 5 (sam05.py)

Опишите функцию right(text), которая выведет на экран строку text. Всего на вывод строки отводится 20 символов. Строка выравнивается по правому краю. Оставшиеся слева место заполняются символом "_". Если строка text длиннее 20 символов, выводятся только первые 20.

Предупреждение

Не используйте в коде решения возможности f-строк, функции format() или методы класса str. Использование функции len(), срезов и арифметических операторов разрешено.

Используйте следующий шаблон:

# вместо этого комментария опишите необходимую функцию


# не исправляйте данный код
right("дата")
right("тема урока")
right("класс")
right("Сегодня контрольная работа")

Пример работы программы:

________________дата
__________тема урока
_______________класс
Сегодня контрольная 

Задание № 6 (sam06.py)

Опишите функцию rating(lum, power), которая рассчитывает и возвращает рейтинг энергоэффективности светодиодной лампочки. Параметр lum - световой поток лампочки (в люменах, лм), power - потребляемая мощность за 1000 часов работы (в кВт·ч/1000ч).

Для расчёта используется коэффициент эффективности:

\[ \text{ratio} = \frac{\text{lum}}{\text{power}} \tag{3}\]

На основе значения ratio функция должна вернуть буквенный рейтинг согласно таблице:

Рейтинг Условие для ratio
"A" ratio > 210
"B" ratio > 185
"C" ratio > 160
"Другой" во всех остальных случаях

Используйте следующий шаблон:

# вместо этого комментария опишите необходимую функцию


# не исправляйте данный код
print(rating(1600, 8))
print(rating(1800, 5))
print(rating(840, 4))
print(rating(1100, 12))

Пример работы программы:

B
A
B
Другой

Вычислите коэффициент эффективности как частное от деления lum на power (формула 3).

Используйте каскадное ветвление if - elif - else для определения рейтинга.

Верните результат из функции с помощью инструкции return.