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

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

Python Workbook Cover T1
  • Операторы: def
  • Контент: Вопросы (6шт) + задачи (5шт)

Оглавление

1
Введение
Определим ситуации использования функций в Python, ознакомимся с основными встроенными (range, print, sum, len и др.). На примере вопросов и задач научимся пользоваться функциями и грамотно их применять на практике.
Перейти
2
Вопросы и ответы
6 вопросов по теме "Функции" + ответы
Перейти
3
Условия задач
5 задач по теме двух уровней сложности: Базовый и *Продвинутый
Перейти
4
Решения задач
Приводим код решений указанных выше задач
Перейти
1
One

Введение

Главные причины применения функций в Python:
  1. Изолирование блоков кода.
  2. Исключение повторного написания программных строк (принцип Don't repeat yourself, Не повторяйся).
Сначала нужно объявить функцию (написать ее код) и лишь затем вызывать. К функциям в Python относят:
  • встроенные (например, range(), len(), int(), chr(). Они доступны в любом скрипте в любое время. Полный список представлен по ссылке: https://docs.python.org/3/library/functions.html);
  • пользовательские (написаны нами для решения возникающих задач. Объявляются конструкцией def);
  • лямбда-функции (анонимные, предваряются словом lambda);
  • импортируемые (из встроенных или сторонних модулей. Для их использования требуется установка библиотеки, если она не встроена, и импорт модуля);
  • методы классов (являются функциями по своему поведению).
При работе с заданиями следует повторить синтаксис написания функций, способы применения встроенных и особенности передачи параметров.

Читайте также

2
Two

Вопросы по теме "Функции"

6*. Охарактеризуйте все возможные виды параметров функций.

Несмотря на кажущуюся простоту в понимании типов параметров функций при их трактовании у начинающих разработчиков часто возникают трудности.
Если коротко, то возможно 4 вида параметров:
– позиционные,
– строго позиционные,
– ключевые,
– строго ключевые.

Для понимания их различий приведем ряд примеров.
Пример – IDE

def my_func(a, b):
    print(a, b)

# Тесты
my_func(2, 4) # Позиционные аргументы
my_func(b=2, a=4) # Ключевые аргументы
my_func(2, b=4) # Первый аргумент – позиционный, второй - ключевой
my_func(a=2, 4) # Позиционные аргументы должны всегда предшествовать ключевым, поэтому в работе кода возникнет ошибка
Параметры a и b являются позиционными, т.е. будут присваиваться аргументам в том порядке, в котором они переданы в функцию. Тем не менее, никто не запрещает сделать их ключевыми, если им присвоить значения перед вызовом.
Результат выполнения

2 4
4 2
2 4
SyntaxError: positional argument follows keyword argument
 
Таким образом, позиционные параметры всегда предшествуют ключевым. В общем случае позиционные аргументы легко превратить в ключевые, если воспользоваться присваиванием. Однако такое поведение можно запретить, если задать строго позиционные аргументы:
Пример – IDE

def my_func(a, b, /):
    print(a, b)

# Тесты
my_func(2, 4)
my_func(b=2, a=4)
Результат выполнения

2 4
TypeError: my_func() got some positional-only arguments passed as keyword arguments: 'a, b'
Знак косой черты свидетельствует о том, что все параметры до нее обязаны быть строго позиционными.
Для задания неограниченного количества позиционных аргументов используют конструкцию *args. Все переменные поступают в тело функции в виде кортежа.
Пример – IDE

def my_func(*args):
    print(args)
 
# Тесты
my_func(2, 4)
my_func()
my_func(2, 4, key=10)
Результат выполнения

(2, 4)
()
TypeError: my_func() got an unexpected keyword argument 'key'
Неограниченное число ключевых параметров задается инструкцией **kwargs. В тело функции они передаются как словарь.
Пример – IDE

def my_func(**kwargs):
    print(kwargs)

# Тесты
my_func()
my_func(a=5, b=10, c=15)
my_func(a=5, b=10, 8)
Результат выполнения

{}
{'a': 5, 'b': 10, 'c': 15}
SyntaxError: positional argument follows keyword argument
 
Чтобы передать в функцию строго ключевые аргументы, их нужно предварить инструкцией * или *args.
Пример – IDE

def my_func(*, a=5, b=10):
    print(a, b)

# Тесты
my_func()
my_func(a=2, b=3)
my_func(b=1, a=10)
my_func(7, b=1, a=10)
Результат выполнения

5 10
2 3
10 1
TypeError: my_func() takes 0 positional arguments but 1 positional argument (and 2 keyword-only arguments) were given
Если не воспользоваться *, то переменные можно интерпретировать как ключевые, так и позиционные со значениями по умолчанию.
Пример – IDE

def my_func(a=5, b=10):
    print(a, b)

# Тесты
my_func()
my_func(a=2, b=3)
my_func(b=1, a=10)
my_func(7, 3)
Результат выполнения

5 10
2 3
10 1
7 3
3
Three

Задачи по теме "Функции"

Задача 1
Напишите функцию sum_range(start, end), которая суммирует все целые числа от значения start до величины end включительно. Если пользователь задаст первое число большее чем второе, просто поменяйте их местами.
Задача 2
Чтобы проверить понимание параметров и область их видимости Николай создал 3 функции (представлены ниже). Попытайтесь предугадать, как поведет себя каждая из них при запуске (возникнут ли ошибки, что возвратится).

Пример – IDE - Функция 1
def func1():
____param = 4

____def inner():
________param += 1

____return param

Пример – IDE - Функция 2
def func2():
_____param = 4

_____def inner(var):
_________var += 1

____inner(param)
____return param

Пример – IDE - Функция 3
def func3():
____param = 4

____def inner(var):
________var += 1
________return var

____param = inner(param)
____return param

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

Пример – IDE
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

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

Решения

Задача 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
Как вам материал?

Читайте также