## ++Тема 2++<br>Расширенные возможности функций (c) Яценко Р.Н., 2019-2022 [Учебный центр компьютерных технологий "Кит"](http://kit.kh.ua/) <img src="https://i.imgur.com/Kh901c1.png" style="width: 150px; position: fixed; top: 10px; right: 10px; border: 0; box-shadow: none;"> --- ## 1. Виды параметров ---- ### Структуризация программы - декомпозиция сложной задачи на несколько более простых подзадач: это один из двух главных инструментов структурного программирование (второй -- структуры данных) - уменьшение дублирования кода и возможность повторного использования кода в нескольких программах -- следование принципу DRY «не повторяйся» (англ. Don’t Repeat Yourself) ---- - распределение большой задачи между несколькими разработчиками или стадиями проекта - сокрытие деталей реализации от пользователей подпрограммы - улучшение отслеживания выполнения кода (большинство языков программирования предоставляет стек вызовов подпрограмм) ---- ### Функции в Python ```python def function_name([parameters]): # Тело функции suite ``` - змеиный_регистр (англ. snake_case) для наименования функций: `my_function` - `parameters`: параметры функции (через запятую) - пустые строки для отделения функций, а большие блоки кода помещать внутрь функций - строки документации ---- ### Пустая функция (stub) - Иногда, когда вы пишете какой-нибудь код, вам нужно просто ввести определения функции, которое не содержит в себе код ```python def empty_function(): pass ``` - Оператор `pass` ничего не делает ---- ### Передача аргументов функции ```python= def add(a, b): return a + b print( add(1, 2) ) # 3 ``` Каждая функция выдает определенный результат. Если вы не указываете на выдачу конкретного результата, она выдаст результат `None` ---- ### Передача параметров и возвращение результата функции ![](https://i.imgur.com/1XpCbb9.png) ---- ### Виды параметров - *позиционные*: указываются простым перечислением: ```python def function_name(a, b, c): # a, b, c - 3 позиционных параметра pass ``` - *ключевые*: указываются перечислением `ключ=значение`: ```python def function_name(key=value, key2=value2): # key, key2 - 2 ключевых параметра # value, value2 - их значения по умолчанию ``` ---- ### Наименование аргументов ```python=6 print( add(a = 2, b = 3) ) # 5 total = add(b = 4, a = 5) print(total) # 9 ``` Не важно, в каком порядке вы будете передавать аргументы функции до тех пор, пока они называются корректно ---- ### Ключевые аргументы ```python= def keyword_function(a=1, b=2): return a+b print(keyword_function(b=4, a=5)) # 9 print(keyword_function()) # Результат - 3 # а и b по умолчанию имеют значение 1 и 2 ``` ---- ### Комбинация параметров **Позиционные параметры всегда идут перед ключевыми**: ```python= def mixed_function(a, b=2, c=3): return a+b+c print( mixed_function(1, b=4, c=5) ) # 10 print( mixed_function(1) ) # 6 print(mixed_function(b=4, c=5)) ``` ``` Traceback (most recent call last): File "<string>", line 1, in <fragment> TypeError: mixed_function() takes at least 1 argument (2 given) ``` --- ## 2. Переменное количество аргументов ---- ### Упаковка аргументов Для переменного количества аргументов используется механизм упаковки аргументов, указав при объявлении параметра в функции один из двух символов: - `*`: все позиционные аргументы начиная с этой позиции и до конца будут собраны в кортеж - `**`: все ключевые аргументы начиная с этой позиции и до конца будут собраны в словарь ---- ### Проблема ```python= def multiply(x, y): print (x * y) print(multiply(5, 4)) # 20 print(multiply(5, 4, 3)) ``` ``` TypeError: multiply() takes 2 positional arguments but 3 were given ``` ---- ### Решение Итак, если вам позже нужно будет использовать больше аргументов, вы можете использовать `*args` в качестве параметра ```python= def multiply(*args): z = 1 for num in args: z *= num print(z) multiply(4, 5) # 20 multiply(10, 9) # 90 multiply(2, 3, 4) # 24 multiply(3, 5, 10, 6) # 900 ``` ---- ### kwargs - `**kwargs` с двумя звездочками используется в качестве параметра для отправки в функции списка аргументов переменной длины без ключевого слова - в функции создается словарь под названием `kwargs`, и мы можем работать с ним так же, как и с другими словарями ---- ### Пример ```python= def print_kwargs(**kwargs): print(kwargs) print_kwargs(kwargs_1="Shark", kwargs_2=4.5, kwargs_3=True) ``` ``` {'kwargs_1': 'Shark', 'kwargs_2': 4.5, 'kwargs_3': True} ``` ---- ### Пример 2 ```python= def print_values(**kwargs): for key, value in kwargs.items(): print(f"Значением для {key} является {value}") print_values(my_name="Глеб", your_name="Сергей") ``` ``` Значение для my_name является Глеб Значение для your_name является Сергей ``` ---- ### Порядок параметров функции - позиционные параметры - `*args` - ключевые параметры - `**kwargs` ```python def example2(arg_1, arg_2, *args, kw_1="shark", kw_2="blobfish", **kwargs): ``` ---- ### Использование `*args` при вызове функции ```python= def some_args(arg_1, arg_2, arg_3): print("arg_1:", arg_1) print("arg_2:", arg_2) print("arg_3:", arg_3) args = ("Глеб", "Сергей", "Кирилл") some_args(*args) ``` ``` arg_1: Глеб arg_2: Сергей arg_3: Кирилл ``` ---- ```python= def some_args(arg_1, arg_2, arg_3): print("arg_1:", arg_1) print("arg_2:", arg_2) print("arg_3:", arg_3) my_list = [2, 3] some_args(1, *my_list) ``` ``` arg_1: 1 arg_2: 2 arg_3: 3 ``` ---- ### Использование `*kwargs` при вызове функции ```python= def some_kwargs(kwarg_1, kwarg_2, kwarg_3): print("kwarg_1:", kwarg_1) print("kwarg_2:", kwarg_2) print("kwarg_3:", kwarg_3) kwargs = { "kwarg_1": "Глеб", "kwarg_2": "Сергей", "kwarg_3": "Кирилл" } some_kwargs(**kwargs) ``` ``` kwarg_1: Глеб kwarg_2: Сергей kwarg_3: Кирилл ``` --- ## 3. Анонимные функции ---- ### Синтаксис лямбда-выражения ```python lambda parameters: expression ``` - `parameters` является необязательной, представляет собой список переменных через запятую (позиционных параметров) - `expression` не может содержать `if, for, while, return` (условные выражения - допустимы) - результатом лямбда-выражения является анонимная функция - Когда лямбда-функция вызывается, она возвращает выражение `expression` ---- ### Пример ```python= import math def sqroot(x): return math.sqrt(x) square_rt = lambda x: math.sqrt(x) print(sqroot(49)) # 7.0 print(square_rt(64)) # 8.0 ``` ---- ### Пример 1 Можно написать лямбда-функцию, которая удваивает свой аргумент: `lambda x: x*2`, и использовать её в функции `map`, чтобы удвоить все элементы в списке ```python= my_list = [1, 2, 3, 4, 5, 6] new_list = list(map(lambda x: x*2, my_list)) print(new_list) # [2, 4, 6, 8, 10, 12] ``` ---- ### Пример 2 Можно создать лямбда-функцию, которая ищет числа больше нуля: `lambda x: x > 0` и использовать в `filter`, чтобы создать список исключительно положительных чисел ```python= my_list = [18, -3, 5, 0, -1, 12] new_list = list(filter(lambda x: x > 0, my_list)) print(new_list) # [18, 5, 12] ``` ---- ### Пример 3 Пользовательская сортировка ```python= elements = [(2, 12, "Mg"), (1, 11, "Na"), (1, 3, "Li"), (2, 4, "Be")] elements.sort(key=lambda x: x[1]) # Сортировка по порядковому номеру print(elements) # [(1, 3, 'Li'), (2, 4, 'Be'), (1, 11, 'Na'), (2, 12, 'Mg')] lst = ["Java", "Algol", "C++"] print(max(lst, key=lambda x: x.count("a"))) def find_a(x): return x.find("a") print(min(lst, key=find_a)) ``` --- ## 4. Рекурсия и мемоизация ---- ### Последовательность Фибоначчи Как вы, вероятно, знаете, последовательность Фибоначчи образуется следующим образом: - складываем первое и второе число, 0 и 1, чтобы получить третье число в последовательности (0 + 1 = 1) - складываем второе и третье число, чтобы получить 4-е число в последовательности (1 + 1 = 2) - и так проделываем для каждого последующего числа Фибоначчи ---- ### Цикл for ```python= def fib_for(n): n1 = 0 n2 = 1 if n <= 0: return 'Введите число больше 0' elif n == 1: return n1 elif n == 2: return n2 else: for i in range(2, n): n1, n2 = n2, n1 + n2 return n2 ``` ---- ### Рекурсия fib(2) = fib(1) + fib(0) = 1 + 0 = 1 ![](https://i.imgur.com/zOmfAZj.png) ---- ### Рекурсия (код) ```python= def fib_recursion(n): if n <= 0: return 'Введите число больше 0' elif n == 1: return 0 elif n == 2: return 1 else: return fib_recursion(n - 1) + fib_recursion(n - 2) ``` ---- ### Мемоизация *Мемоизация* – это метод, который может значительно улучшить производительность рекурсивной функции за счет уменьшения вычислительных затрат. Он сохраняет результаты дорогостоящих вызовов функций в массиве или словаре и при вызове с такими же входными данными возвращает кэшированные результаты. ---- ### Мемоизация (код) ```python= def Fib_memoisation(n, memo): if n <= 0: return 'Введите число больше 0' elif n == 1: return 0 elif n == 2: return 1 else: if n not in memo: memo[n] = Fib_memoisation(n - 1, memo) \ + Fib_memoisation(n - 2, memo) return memo[n] ``` --- ## 5. Документирование кода ---- ### Строки документации - Python предоставляет возможность добавить документацию (описание) к любой функции, используя строки документирования - Это обычные строки в тройных кавычках `"""`, которые следуют сразу за строкой с инструкцией def перед программным кодом функции и воспринимаются транслятором специальным образом - Соглашения по документированию функций содержатся в документе [PEP 257](https://www.python.org/dev/peps/pep-0257/) ---- ### Документирование функций ```python= # Для небольшой функции можно использовать одну строку # Как правило, это описание действия в повелительном наклонении def sqrt(x): """Вернуть квадратный корень из 'x'.""" return x**0.5 ``` ---- ### Многострочное документирование ```python= def heron(a, b, c): """Вернуть площадь треугольника по формуле Герона. Параметры: - a, b, c (float): стороны треугольника. Результат: - float: значение площади. - None: если треугольник не существует. """ if not (a + b > c and a + c > b and b + c > a): return p = (a + b + c) / 2 return sqrt(p * (p - a) * (p - b) * (p - c)) ``` ---- ### Получение документации ```python= # Справочную информацию о функции можно получить 2 способами: # heron.__doc__ или help(heron) print(heron.__doc__) ``` ``` Вернуть площадь треугольника по формуле Герона. Параметры: - a, b, c (float): стороны треугольника. Результат: - float: значение площади. - None: если треугольник не существует. ``` --- ## Спасибо за внимание! ![](https://i.imgur.com/gKDsna4.png) (c) Яценко Р.Н., 2018-2022 [Учебный центр компьютерных технологий "Кит"](http://kit.kh.ua/) <!-- - Источники - https://python-scripts.com/functions-python - https://python-scripts.com/def-args-kwargs - https://python-scripts.com/lambda - https://www.yuripetrov.ru/edu/python/ch_05_01.html - [Лямбда-функции в Python: примеры](https://pythonist.ru/lyambda-funkczii-v-python-primery) - [Мемоизация, рекурсия и цикл for в Python](https://pythonist.ru/memoizacziya-rekursiya-i-czikl-for-v-python/) > Рассмотрим мемоизацию, рекурсию и цикл for для создания чисел Фибоначчи -->
{"metaMigratedAt":"2023-06-15T16:39:13.871Z","metaMigratedFrom":"YAML","title":"Тема 2. Расширенные возможности функций","breaks":false,"slideOptions":"{\"allottedMinutes\":80,\"transition\":\"slide\",\"theme\":\"beige\",\"slideNumber\":\"c\",\"spotlight\":{\"enabled\":true}}","description":"© Яценко Р.Н., 2019-2022","contributors":"[{\"id\":\"93a8c43f-1b5b-4461-9101-89b183ccbc1c\",\"add\":12742,\"del\":773}]"}
    463 views