🐍 Самоучитель по Python для начинающих. Часть 11: Функции с позиционными и именованными аргументами

Разберемся, как передавать в функцию произвольное число аргументов, как задавать и изменять параметры по умолчанию, и как возвращать результаты работы в основную программу. В конце статьи – 10 практических задач.

Функция – это мини-программа внутри основной программы. Код такой подпрограммы отвечает за решение определенной задачи: например, в игре Тетрис будут отдельные функции для подсчета очков, рисования игрового поля, движения фигурки и так далее. Использование функций позволяет:

  • ограничить область видимости переменных функциями, которые их используют;
  • исключить дублирование кода;
  • разбить большую и сложную программу на небольшие мини-программы, которые можно вызывать в нужный момент;
  • выстроить простую и понятную структуру программы – такой код удобнее дебажить и поддерживать.

У функций есть несколько особенностей:

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

Функции в Python

Python работает со встроенными и пользовательскими функциями. Встроенные функции – это уже знакомые нам print(), input(), map(), zip() и так далее. Пользовательские функции, в свою очередь, делятся на:

  • Рекурсивные (вызывают сами себя до тех пор, пока не будет достигнут нужный результат).
  • Анонимные, или лямбда-функции (объявляются в любом участке кода и сразу же вызываются).
  • Все остальные функции, которые определены пользователем и не относятся ни к рекурсивным, ни к анонимным.

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

🐍🎓 Библиотека собеса по Python
Подтянуть свои знания по Python вы можете на нашем телеграм-канале «Библиотека собеса по Python»
🐍🧩 Библиотека задач по Python
Интересные задачи по Python для практики можно найти на нашем телеграм-канале «Библиотека задач по Python»

Объявление и вызов функций в Python

Для создания функции используют ключевое слово def. Вот пример простейшей функции, которая не получает и не возвращает никаких данных – просто выполняет одну команду по выводу строки с приветствием:

def my_function():
  print('Привет от Python')

Для вызова такой функции достаточно написать ее название:

my_function()

Результат вызова:

Привет от Python

А это пример простейшей функции с параметром:

def my_function(name):
    print(f'Привет, {name}')

При вызове функция получает аргумент:

my_function('Вася')

Результат вызова:

Привет, Вася

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

def my_function(name, lastname):
    print(f'Добрый день, {name} {lastname}')

Если передать в функцию два аргумента – my_function('Егор', 'Куликов'), результат вызова будет таким:

Добрый день, Егор Куликов

Но если число аргументов окажется меньше числа параметров – my_function('Алена'), возникнет ошибка:

    my_function('Алена')
TypeError: my_function() missing 1 required positional argument: 'lastname'
🐍 Библиотека питониста
Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека питониста»

Порядок обработки позиционных аргументов

Python обрабатывает позиционные аргументы слева направо:

def my_function(name, last_name, occupation, age):
    print(f'Сотрудник #1 - {name} {last_name} {occupation} {age}')

info1, info2, info3, info4 = 'Алиса', 'Селезнева', 'скрам-мастер', 30
my_function(info1, info2, info3, info4)                  
my_function(info2, info3, info1, info4)                 
my_function(info4, info1, info2, info3)                 

Вывод:

Сотрудник #1 - Алиса Селезнева скрам-мастер 30
Сотрудник #1 - Селезнева скрам-мастер Алиса 30
Сотрудник #1 - 30 Алиса Селезнева скрам-мастер

Аргументы по умолчанию

Функция может использовать аргументы по умолчанию – они указываются после позиционных:

def my_function(strt, build, ap, city='Москва'):
    print(f'Адрес: г.{city}, ул.{strt}, д.{build}, кв.{ap}')
my_function('Красная', '5', '3', 'Тула')
my_function('Красная', '5', '3')
Результат:
Адрес: г.Тула, ул.Красная, д.5, кв.3
Адрес: г.Москва, ул.Красная, д.5, кв.3

Именованные аргументы

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

def sales_price(price, discount=5):
    return price - price * discount / 100

print(sales_price(5000))
print(sales_price(5000, discount=10))
print(sales_price(discount=15, price=5000))

Вывод:

4750.0
4500.0
4250.0

Произвольное количество позиционных аргументов *args

До сих пор мы передавали в функцию определенное, заранее известное число позиционных аргументов. Если в функцию нужно передать произвольное количество аргументов, используют *args:

def my_function(*args):
    print(f'Минимальное число: {min(args)}, максимальное: {max(args)}')
my_function(1, 4, 5, 2, -5, 0, 12, 11)  

Результат вызова:

Минимальное число: -5, максимальное: 12

При использовании *args функция получает кортеж аргументов, и к ним можно обращаться так же, как к элементам кортежа:

def my_function(*args):
    print(f'Первое слово: {args[0]}, последнее слово: {args[-1]}')
my_function('яблоко', 'виноград', 'апельсин', 'арбуз', 'слива', 'груша')

Результат вызова:

Первое слово: яблоко, последнее слово: груша

Название набора параметров, *args, используется по умолчанию. При желании его можно изменить на любое другое название с * в начале:

def my_function(*cities):
    print(f'Первый город: {cities[0]}, третий город: {cities[2]}')
my_function('Тюмень', 'Москва', 'Орел', 'Новгород', 'Ижевск', 'Ульяновск')  

Результат вызова:

Первый город: Тюмень, третий город: Орел

Аргументы *args обрабатываются после позиционных, но до аргументов по умолчанию:

def my_function(x, y, *args, kx=15, ky=15):
    print(x, y, args, kx, ky)
my_function(5, 6, 7, 8, 9, 0, 4)  

Вывод:

5 6 (7, 8, 9, 0, 4) 15 15

Произвольное количество именованных аргументов **kwargs

Как уже было отмечено выше, именованные аргументы передаются в функцию в виде пар ключ=значение:

def my_function(cat1, cat2, cat3):
    print(f'Младший кот: {cat1}, старший кот: {cat2}')
my_function(cat1='Том', cat2='Барсик', cat3='Полосатик')  

Результат вызова:

Младший кот: Том, старший кот: Барсик

В приведенном выше примере количество именованных аргументов известно заранее. Если в функцию нужно передать произвольное количество пар ключ=значение, используют параметр **kwargs. С **kwargs работают все методы словарей:

def my_function(**kwargs):
    print(f'Самый легкий металл - {min(kwargs, key=kwargs.get)} {min(kwargs.values())}, самый тяжелый - {max(kwargs, key=kwargs.get)} {max(kwargs.values())}')
my_function(осмий=22.61, цинк=7.1, золото=19.3, ртуть=13.6, олово=7.3)

Результат вызова:

Самый легкий металл - цинк 7.1, самый тяжелый - осмий 22.61

Как и в случае с *args, название по умолчанию **kwargs при желании можно заменить на любое другое с ** в начале:

def my_function(**countries):
    print(f'Самая густонаселенная страна - {max(countries, key=countries.get)} {max(countries.values())} чел/км2, самая малонаселенная - {min(countries, key=countries.get)} {min(countries.values())} чел/км2')
my_function(Мальта=1432, Дания=128, Монако=18679, Индия=357, Монголия=2)  

Результат вызова:

Самая густонаселенная страна - Монако 18679 чел/км2, самая малонаселенная - Монголия 2 чел/км2

Аргументы типа **kwargs обрабатываются после позиционных, *args и аргументов по умолчанию:

def my_function(x, y, *args, kx=15, ky=15, **kwargs):
    print(x, y, args, kx, ky, kwargs)
my_function(7, 8, 0, 3, 4, 1, 8, 9, север=15, запад=25, восток=45, юг=10)

Вывод:

 7 8 (0, 3, 4, 1, 8, 9) 15 15 {'север': 15, 'запад': 25, 'восток': 45, 'юг': 10}

Передача аргументов в виде списка

Помимо кортежей и словарей, в функции можно передавать списки:

def my_function(stationery):
    for i, j in enumerate(stationery):
        print(f'Товар #{i + 1} - {j}')
        
stuff = ['карандаш', 'ручка', 'блокнот', 'альбом', 'тетрадь', 'ластик']   
my_function(stuff)

Результат вызова:

Товар #1 - карандаш
Товар #2 - ручка
Товар #3 - блокнот
Товар #4 - альбом
Товар #5 - тетрадь
Товар #6 - ластик

Заглушка pass

Тело функции не может быть пустым – это приведет к сообщению об ошибке:

def my_function():
Вывод:
    def my_function():
                     ^
SyntaxError: unexpected EOF while parsing

Если по какой-то причине нужно оставить тело функции пустым, используют оператор pass, который выступает в роли заглушки:

def my_function():
    pass

Функции с возвратом значений

Как уже было показано выше, функции могут получать и обрабатывать любые типы данных – строки, числа, списки, кортежи, словари. Результат обработки можно получить с помощью оператора return. Эта функция возвращает произведение произвольного количества значений:

def my_function(*args):
    prod = 1
    for i in args:
        prod *= i
    return prod    
print(my_function(5, 6, 3, 11))

Значения передаются в функцию при вызове – print(my_function(5, 6, 3, 11)). Результат при таком наборе цифр будет равен 990. Оператор return может возвращать любое количество значений, причем значения возвращаются в виде кортежа:

def calculations(a, b):
    summa = a + b
    diff = a - b
    mul = a * b
    div = a / b
    return summa, diff, mul, div
num1, num2 = int(input()), int(input())
summa, diff, mul, div = calculations(num1, num2)
print(
    f'Сумма: {summa}\n'
    f'Разница: {diff}\n'
    f'Произведение: {mul}\n'
    f'Результат деления: {div:.2f}\n'
    )

Пример ввода:

49
6

Вывод:

Сумма: 55
Разница: 43
Произведение: 294
Результат деления: 8.17

Функция может содержать любое количество return. Эта функция возвращает различные оценки индекса массы тела:

def bmi(h, w):
    bmi = w / (h / 100) ** 2
    if bmi <= 18.5:  
        return 'У вас дефицит веса' 
    elif bmi <= 24.9:  
        return 'Вес в норме' 
    elif bmi <= 29.9:  
        return 'Есть лишний вес'
    else:  
        return 'Срочно на диету!'
h = float(input('Введите рост в см: '))  
w = float(input('Введите вес в кг: '))
print(bmi(h, w))

Пример ввода:

Введите рост в см: 172
Введите вес в кг: 61

Вывод:

Вес в норме

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

def bmi(h, w):
    bmi = w / (h / 100) ** 2
    if bmi <= 18.5:  
        res = 'У вас дефицит веса' 
    elif bmi <= 24.9:  
        res = 'Вес в норме' 
    elif bmi <= 29.9:  
        res = 'Есть лишний вес'
    else:  
        res = 'Срочно на диету!'
    return res    
h = float(input('Введите рост в см: '))  
w = float(input('Введите вес в кг: '))
print(bmi(h, w))

Практика

Задание 1

Напишите функцию для вывода треугольника. Функция принимает два аргумента – size (размер сторон треугольника) и symb (символ, используемый для заполнения треугольника).

Пример ввода:

9
.

Вывод:

.
..
...
....
.....
....
...
..
. 

Решение:

def draw_triangle(size, symb):
    for i in range(1, size + 1):
        print(symb * min(i, size - i + 1))

size, symb = int(input()), input()
draw_triangle(size, symb)

Задание 2

Напишите функцию, которая принимает произвольное количество целых чисел, и возвращает среднее арифметическое без использования встроенных функции sum() и len().

Пример вызова:

print(arith_mean(5, 5, 15, 25, 35))

Вывод:

17.0

Решение:

def arith_mean(*args):
    summa = 0
    kol = 0
    for i in args:
        summa += i
        kol += 1
    return summa / kol

Задание 3

Напишите функцию, которая:

  • принимает строку, состоящую из букв, цифр и специальных символов;
  • формирует три списка – 1) из цифр, 2) из букв, 3) из спецсимволов;
  • выводит списки на экран.

Пример ввода:

23edwd893rjf934#$%Ye34F^(*))_+W$#Ddq2ddscew3r

Вывод:

2 3 8 9 3 9 3 4 3 4 2 3
e d w d r j f Y e F W D d q d d s c e w r
# $ % ^ ( * ) ) _ + $ #

Решение:

def sort_list(st):
    digits = [i for i in st if i.isdigit()]
    letters = [i for i in st if i.isalpha()]
    spec_char = [i for i in st if not i.isalnum()]
    print(*digits)
    print(*letters)
    print(*spec_char)
my_st = input()
sort_list(my_st)

Задание 4

Напишите функцию, которая начисляет новогодние премии сотрудникам. Эта функция:

  • имеет два аргумента по умолчанию – salary=120000 и bonus=10 (оклад и премия);
  • получает два позиционных аргумента name и last_name – имя и фамилию сотрудника;
  • учитывает индивидуальные оклад и премию (см. примеры вызова);
  • выводит размер новогодней премии для сотрудника и зарплату с учетом премии.

Примеры вызова функции:

ny_bonus('Алина', 'Тимофеева', salary=150000, bonus=25)
ny_bonus('Алексей', 'Ковалев', bonus=15)
ny_bonus('Игорь', 'Ефимов')
ny_bonus('Анастасия', 'Яковлева', salary=100000, bonus=20) 

Вывод:

Новогодняя премия сотрудника Алина Тимофеева: 37500.00 руб.
Оклад: 150000.00 руб.
Всего к выдаче: 187500.00 руб.

Новогодняя премия сотрудника Алексей Ковалев: 18000.00 руб.
Оклад: 120000.00 руб.
Всего к выдаче: 138000.00 руб.

Новогодняя премия сотрудника Игорь Ефимов: 12000.00 руб.
Оклад: 120000.00 руб.
Всего к выдаче: 132000.00 руб.

Новогодняя премия сотрудника Анастасия Яковлева: 20000.00 руб.
Оклад: 100000.00 руб.
Всего к выдаче: 120000.00 руб.

Решение:

def ny_bonus(name, last_name, salary=120000, bonus=10):
    print(f'Новогодняя премия сотрудника {name} {last_name}: {salary * bonus / 100:.2f} руб.\n'
          f'Оклад: {salary:.2f} руб.\n'
          f'Всего к выдаче: {salary + salary * bonus / 100:.2f} руб.\n')

Задание 5

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

Пример ввода:

5 7 8 9 34 28

Вывод:

Есть

Решение:

def perfect_number(n):
    sum = 0
    for i in range(1, n):
        if n % i == 0:
            sum += i
    return sum == n
numbers = list(map(int, input().split()))
flag = 'Нет'
for i in numbers:
    if perfect_number(i):
        flag = 'Есть'
        break
print(flag)

Задание 6

Напишите функцию, которая принимает два позиционных аргумента – натуральные числа n и k, и возвращает значение биномиального коэффициента, не используя math.factorial().

Пример ввода:

12
5

Вывод:

792

Решение:

def factorial(num):
    if num <= 1:
        return 1
    return num * factorial(num - 1)

def binomial_coeff(n, k):
    return int(factorial(n) / (factorial(k) * factorial(n - k)))

n, k = int(input()), int(input())
print(binomial_coeff(n, k))

Задание 7

Напишите функцию, которая принимает число от 1 до 99, и возвращает его словесное описание.

Пример ввода:

25

Вывод:

двадцать пять

Решение:

def spell_number(num):
    ed = ['один', 'два', 'три', 'четыре', 'пять', 'шесть', 'семь', 'восемь', 'девять', 'десять', 'одиннадцать', 'двенадцать', 'тринадцать', 'четырнадцать', 'пятнадцать', 'шестнадцать', 'семнадцать', 'восемнадцать', 'девятнадцать']
    des = ['двадцать', 'тридцать', 'сорок', 'пятьдесят', 'шестьдесят', 'семьдесят', 'восемьдесят', 'девяносто']
    if num < 20:
        return ed[num - 1]
    elif num >= 20:
        if str(num)[1] != '0':
            return des[int(str(num)[0]) - 2] + ' ' + ed[int(str(num)[1]) - 1]
    return des[int(str(num)[0]) - 2]     

n = int(input())
print(spell_number(n))

Задание 8

Напишите функцию, которая возвращает True, если введенная пользователем дата является магической, и False в обратном случае. Магической считается дата, в которой произведение дня и месяца равно двум последним цифрам года: 02.11.2022.

Пример ввода:

03.06.2018

Вывод:

True

Решение:

def magic_date(date):
    return int(date[:2]) * int(date[3:5]) == int(date[-2:])

date = input()
print(magic_date(date))

Задание 9

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

Примеры вызова:

print(make_query(category='books', genre='thriller', author='Stephen_King'))  
print(make_query(name='Егор', last_name='Тимохин', age=25, occupation='дизайнер'

Вывод:

author=Stephen_King&category=books&genre=thriller
age=25&last_name=Тимохин&name=Егор&occupation=дизайнер

Решение:

def make_query(**kwargs):
    return '&'.join([f'{k}={kwargs[k]}' for k in sorted(kwargs)]) 

Задание 10

Напишите функцию, которая принимает целое число n, и выводит на экран спиральную матрицу размера n x n, все элементы которой выровнены по левому краю.

Пример ввода:

9

Вывод:

1  2  3  4  5  6  7  8  9  
32 33 34 35 36 37 38 39 10 
31 56 57 58 59 60 61 40 11 
30 55 72 73 74 75 62 41 12 
29 54 71 80 81 76 63 42 13 
28 53 70 79 78 77 64 43 14 
27 52 69 68 67 66 65 44 15 
26 51 50 49 48 47 46 45 16 
25 24 23 22 21 20 19 18 17 

Решение:

def print_matrix(n):
    matrix = [[0] * n for i in range(n)]
    vx, vy = [0, 1, 0, -1], [1, 0, -1, 0]
    x, y, z = 0, -1, 1
    for i in range(n + n - 1):
        for j in range((n + n - i) // 2):
            x += vx[i % 4]
            y += vy[i % 4]
            matrix[x][y] = z
            z += 1
    for i in range(len(matrix)):
        for j in range(len(matrix[i])):
            print(str(matrix[i][j]).ljust(3), end='')  
        print()    
print_matrix(int(input())) 

Подведем итоги

В этой статье мы научились создавать пользовательские функции и передавать в них определенное число позиционных и именованных аргументов, а также произвольное количество значений *args и **kwargs.

В следующей статье будем разбирать анонимные лямбда-функции.

***

Содержание самоучителя

  1. Особенности, сферы применения, установка, онлайн IDE
  2. Все, что нужно для изучения Python с нуля – книги, сайты, каналы и курсы
  3. Типы данных: преобразование и базовые операции
  4. Методы работы со строками
  5. Методы работы со списками и списковыми включениями
  6. Методы работы со словарями и генераторами словарей
  7. Методы работы с кортежами
  8. Методы работы со множествами
  9. Особенности цикла for
  10. Условный цикл while
  11. Функции с позиционными и именованными аргументами
  12. Анонимные функции
  13. Рекурсивные функции
  14. Функции высшего порядка, замыкания и декораторы
  15. Методы работы с файлами и файловой системой
  16. Регулярные выражения
  17. Основы скрапинга и парсинга
  18. Основы ООП: инкапсуляция и наследование
  19. Основы ООП – абстракция и полиморфизм
  20. Графический интерфейс на Tkinter
  21. Основы разработки игр на Pygame
  22. Основы работы с SQLite
  23. Основы веб-разработки на Flask
  24. Основы работы с NumPy
  25. Основы анализа данных с Pandas
***
Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека питониста»

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ

admin
11 декабря 2018

ООП на Python: концепции, принципы и примеры реализации

Программирование на Python допускает различные методологии, но в его основе...
admin
28 июня 2018

3 самых важных сферы применения Python: возможности языка

Существует множество областей применения Python, но в некоторых он особенно...
admin
13 февраля 2017

Программирование на Python: от новичка до профессионала

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