[ Сборник задач ] Тема 11. Функции

Главные причины применения функций в Python:

  1. Изолирование блоков кода.
  2. Исключение повторного написания программных строк (принцип Don’t repeat yourselfНе повторяйся).

Сначала нужно объявить функцию (написать ее код) и лишь затем вызывать. К функциям в Python относят:

  • встроенные (например, range()len()int()chr(). Они доступны в любом скрипте в любое время. Полный список представлен по ссылке: https://docs.python.org/3/library/functions.html);
  • пользовательские (написаны нами для решения возникающих задач. Объявляются конструкцией def);
  • лямбда-функции (анонимные, предваряются словом lambda);
  • импортируемые (из встроенных или сторонних модулей. Для их использования требуется установка библиотеки, если она не встроена, и импорт модуля);
  • методы классов (являются функциями по своему поведению).

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

Задача 1. Базовый уровень

Условие

Напишите функцию sum_range(start, end), которая суммирует все целые числа от значения «start» до величины «end» включительно. 
Если пользователь задаст первое число большее чем второе, просто поменяйте их местами.

При решении удобно воспользоваться встроенными функциями range() и sum().
Пример – IDE

def sum_range(start, end):
    if start > end:
        end, start = start, end
    return sum(range(start, end + 1))

# Тесты
print(sum_range(2, 12))
print(sum_range(-4, 4))
print(sum_range(3, 2))

Результат выполнения

77
0
5

Задача 2. Базовый уровень

Условие

Чтобы проверить понимание параметров и область их видимости, Николай создал 3 функции (представлены ниже). 
Попытайтесь предугадать, как поведет себя каждая из них при запуске (возникнут ли ошибки, что возвратится).
 
Пример – IDE
def func1():
    param = 4
 
    def inner():
        param += 1
 
    return param
 
 
def func2():
    param = 4
 
    def inner(var):
        var += 1
 
    inner(param)
    return param
 
 
def func3():
    param = 4
 
    def inner(var):
        var += 1
        return var
 
    param = inner(param)
    return param

Как ни странно, никаких ошибок при вызове функций мы не увидели.
# Тесты

print(func1())
print(func2())
print(func3())

Результат выполнения

4
4
5

Тем не менее, попробуем разобраться в каждом представленном случае.
1) Первая функция
Во внутренней функции мы пытаемся воспользоваться внешней переменной. Но она не доступна. Ошибки не возникло по единственной причине: мы эту функцию не вызвали.
2) Вторая функция
Внутренняя функция увеличила значение переменной на 1, но сама она ничего не возвращает (кроме None), поэтому значение param не поменялось.
3) Третья функция
В данном случае вернулось 5, так как мы во внутренней функции увеличили внешнюю переменную и присвоили результат в func3.

Задача 3. Базовый уровень

Условие

Создайте функцию three_args(), которая принимает 1, 2 или 3 строго ключевых параметра. 
В результате ее работы на печать в консоль выводятся значения переданных переменных, но только если они не равны None. 
Получим, например, следующее сообщение: «Переданы аргументы: var1 = 2, var3 = 10».

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

Проще всего решить задачу использовав функцию locals(), которая в виде словаря представит все внутренние аргументы функции.
Пример – IDE

def three_args(*, var1, var2=None, var3=None):
    arguments = ', '.join([f'{arg[0]} = {str(arg[1])}' for arg in locals().items() if arg[1] is not None])
    print(f'Переданы аргументы: {arguments}')

# Тесты
three_args(var1=21)
three_args(var1='Python', var3=3)
three_args(var1='Python', var2=3, var3=9)

Результат выполнения

Переданы аргументы: var1 = 21
Переданы аргументы: var1 = Python, var3 = 3
Переданы аргументы: var1 = Python, var2 = 3, var3 = 9

Задача 4. *Продвинутый уровень

Условие

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

from datetime import datetime
from time import sleep
 
 
def time_now(msg, *, dt=datetime.now()):
    print(msg, dt)
 
 
# Тесты
time_now('Сейчас такое время: ')
sleep(1)
time_now('Прошла секунда: ')
sleep(1)
time_now('Ничего не понимаю... ')
 
Результат выполнения
Сейчас такое время:  2021-03-14 15:48:55.117455
Прошла секунда:  2021-03-14 15:48:55.117455
Ничего не понимаю...  2021-03-14 15:48:55.117455

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

Чтобы исправить ситуацию, потребуется вызов значений текущего времени при выполнении функции, а не при ее создании. Если нам все же нужен параметр dt по каким-то причинам (вдруг, мы захотим передать другую дату, а не текущую), то логичнее присвоить ему значение None изначально.
Пример — IDE

from datetime import datetime
from time import sleep
 
 
def time_now(msg, *, dt=None):
    dt = dt or datetime.now()
    print(msg, dt)

# Тесты
time_now('Сейчас такое время: ')
sleep(1)
time_now('Прошла секунда: ')
sleep(1)
time_now('Задам-ка другую дату: ', dt='2020-01-11 11:00:10')

Результат выполнения

Сейчас такое время:  2021-03-14 16:01:53.331533
Прошла секунда:  2021-03-14 16:01:54.331609
Задам-ка другую дату:  2020-01-11 11:00:10

Задача 5. *Продвинутый уровень

Условие

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

В данном случае на подмогу приходит модуль inspect. С его помощью можно реализовать задуманный функционал.
Пример — IDE

import inspect
import math
 
 
def inspect_function(some_func):
	print(f'Анализируем функцию {some_func.__name__}')
	for param in inspect.signature(some_func).parameters.values():
    	print(param.name, param.kind, sep=': ')

# Некая функция для анализа
def my_func(a, b, /, c, d, *args, e, f, **kwargs):
	pass

# Тесты
inspect_function(my_func)
print('-' * 25)
inspect_function(math.sqrt)

Результат выполнения

Анализируем функцию my_func
a: POSITIONAL_ONLY
b: POSITIONAL_ONLY
c: POSITIONAL_OR_KEYWORD
d: POSITIONAL_OR_KEYWORD
args: VAR_POSITIONAL
e: KEYWORD_ONLY
f: KEYWORD_ONLY
kwargs: VAR_KEYWORD
-------------------------
Анализируем функцию sqrt
x: POSITIONAL_ONLY

Добавить комментарий

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