Как написать функцию на питоне пример

Введение

Определение

Вот пример простой функции:

def compute_surface(radius):
    from math import pi
    return pi * radius * radius

Для определения функции нужно всего лишь написать ключевое слово def перед ее именем, а после — поставить двоеточие. Следом идет блок инструкций.

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

i = 0
def increment():
    global i
    i += 1

Функция инкрементирует глобальную переменную i и возвращает None (по умолчанию).

Вызовы

Для вызова функции, которая возвращает переменную, нужно ввести:

surface = compute_surface(1.)

Для вызова функции, которая ничего не возвращает:

increment()

Еще

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

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

Функции могут быть вложенными:

def func1(a, b):

    def inner_func(x):
        return x*x*x

    return inner_func(a) + inner_func(b)

Функции — это объекты, поэтому их можно присваивать переменным.

Инструкция return

Возврат простого значения

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

Возврат нескольких значений

Пока что функция возвращала только одно значение или не возвращала ничего (объект None). А как насчет нескольких значений? Этого можно добиться с помощью массива. Технически, это все еще один объект. Например:

def stats(data):
    """данные должны быть списком"""
    _sum = sum(data) # обратите внимание на подчеркивание, чтобы избежать переименования встроенной функции sum
    mean = _sum / float(len(data)) # обратите внимание на использование функции float, чтобы избежать деления на целое число
    variance = sum([(x-mean)**2/len(data) for x in data])
    return mean,variance   # возвращаем x,y — кортеж!

m, v = stats([1, 2, 1])

Аргументы и параметры

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

Параметр — это имя в списке параметров в первой строке определения функции. Он получает свое значение при вызове. Аргумент — это реальное значение или ссылка на него, переданное функции при вызове. В этой функции:

def sum(x, y):
    return x + y

x и y — это параметры, а в этой:

sum(1, 2)

1 и 2 — аргументы.

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

def compute_surface(radius, pi=3.14159):
    return pi * radius * radius

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

Выходит, что в следующем примере допущена ошибка:

def compute_surface(radius=1, pi):
    return pi * radius * radius

Для вызовов это работает похожим образом. Сначала нужно указывать все позиционные аргументы, а только потом необязательные:

S = compute_surface(10, pi=3.14)

На самом деле, следующий вызов корректен (можно конкретно указывать имя позиционного аргумента), но этот способ не пользуется популярностью:

S = compute_surface(radius=10, pi=3.14)

А этот вызов некорректен:

S = compute_surface(pi=3.14, 10)

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

def compute_surface2(radius=1, pi=3.14159):
    return pi * radius * radius
S = compute_surface2(radius=1, pi=3.14)
S = compute_surface2(pi=3.14, radius=10.)
S = compute_surface2(radius=10.)

Можно не указывать ключевые слова, но тогда порядок имеет значение. Он должен соответствовать порядку параметров в определении:

S = compute_surface2(10., 3.14)
S = compute_surface2(10.)

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

def f(a=1,b=2, c=3):
    return a + b + c

Второй аргумент можно пропустить:

f(1,,3)

Чтобы обойти эту проблему, можно использовать словарь:

params = {'a':10, 'b':20}
S = f(**params)

Значение по умолчанию оценивается и сохраняется только один раз при определении функции (не при вызове). Следовательно, если значение по умолчанию — это изменяемый объект, например, список или словарь, он будет меняться каждый раз при вызове функции. Чтобы избежать такого поведения, инициализацию нужно проводить внутри функции или использовать неизменяемый объект:

def inplace(x, mutable=[]):
   mutable.append(x)
   return mutable
res = inplace(1)
res = inplace(2)
print(inplace(3))
[1, 2, 3]
def inplace(x, lst=None):
   if lst is None: lst=[]
   lst.append()
   return lst

Еще один пример изменяемого объекта, значение которого поменялось при вызове:

def change_list(seq):
    seq[0] = 100
original = [0, 1, 2]
change_list(original)
original
[100, 1, 2]

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

original = [0, 1, 2]
change_list(original[:])
original
[0, 1, 2]

Указание произвольного количества аргументов

Позиционные аргументы

Иногда количество позиционных аргументов может быть переменным. Примерами таких функций могут быть max() и min(). Синтаксис для определения таких функций следующий:

def func(pos_params, *args):
    block statememt

При вызове функции нужно вводить команду следующим образом:

func(pos_params, arg1, arg2, ...)

Python обрабатывает позиционные аргументы следующим образом: подставляет обычные позиционные аргументы слева направо, а затем помещает остальные позиционные аргументы в кортеж (*args), который можно использовать в функции.

Вот так:

def add_mean(x, *data):
    return x + sum(data)/float(len(data))

add_mean(10,0,1,2,-1,0,-1,1,2)
10.5

Если лишние аргументы не указаны, значением по умолчанию будет пустой кортеж.

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

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

def func(pos_params, *args, **kwargs):
    block statememt

При вызове функции нужно писать так:

func(pos_params, kw1=arg1, kw2=arg2, ...)

Python обрабатывает аргументы-ключевые слова следующим образом: подставляет обычные позиционные аргументы слева направо, а затем помещает другие позиционные аргументы в кортеж (*args), который можно использовать в функции (см. предыдущий раздел). В конце концов, он добавляет все лишние аргументы в словарь (**kwargs), который сможет использовать функция.

Есть функция:

def print_mean_sequences(**kwargs):
    def mean(data):
        return sum(data)/float(len(data))
    for k, v in kwargs.items():
        print k, mean(v)

print_mean_sequences(x=[1,2,3], y=[3,3,0])
y 2.0
x 2.0

Важно, что пользователь также может использовать словарь, но перед ним нужно ставить две звездочки (**):

print_mean_sequences(**{'x':[1,2,3], 'y':[3,3,0]})
y 2.0
x 2.0

Порядок вывода также не определен, потому что словарь не отсортирован.

Документирование функции

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

def sum(s,y): return x + y

Если изучить ее, обнаружатся два скрытых метода (которые начинаются с двух знаков нижнего подчеркивания), среди которых есть __doc__. Он нужен для настройки документации функции. Документация в Python называется docstring и может быть объединена с функцией следующим образом:

def sum(x, y):
    """Первая срока - заголовок

    Затем следует необязательная пустая строка и текст 
    документации.
    """
    return x+y

Команда docstring должна быть первой инструкцией после объявления функции. Ее потом можно будет извлекать или дополнять:

print(sum.__doc__)
sum.__doc__ += "some additional text"

Методы, функции и атрибуты, связанные с объектами функции

Если поискать доступные для функции атрибуты, то в списке окажутся следующие методы (в Python все является объектом — даже функция):

sum.func_closure   sum.func_defaults  sum.func_doc       sum.func_name
sum.func_code      sum.func_dict      sum.func_globals

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

>>> sum.__name__
"sum"
>>> sum.__module
"__main__"

Есть и другие. Вот те, которые не обсуждались:

sum.__call__          sum.__delattr__       sum.__getattribute__     sum.__setattr__
sum.__class__         sum.__dict__          sum.__globals__       sum.__new__           sum.__sizeof__
sum.__closure__       sum.__hash__          sum.__reduce__        sum.__str__
sum.__code__          sum.__format__        sum.__init__          sum.__reduce_ex__     sum.__subclasshook__
sum.__defaults__      sum.__get__           sum.__repr__

Рекурсивные функции

Рекурсия — это не особенность Python. Это общепринятая и часто используемая техника в Computer Science, когда функция вызывает сама себя. Самый известный пример — вычисление факториала n! = n * n — 1 * n -2 * … 2 *1. Зная, что 0! = 1, факториал можно записать следующим образом:

def factorial(n):
    if n != 0:
        return n * factorial(n-1)
    else:
        return 1

Другой распространенный пример — определение последовательности Фибоначчи:

f(0) = 1
f(1) = 1
f(n) = f(n-1) + f(n-2)

Рекурсивную функцию можно записать так:

def fibbonacci(n):
    if n >= 2:
        else:
    return 1

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

def factorial(n):
    assert n > 0
    if n != 0:
        return n * factorial(n-1)
    else:
        return 1

Важно!
Рекурсия позволяет писать простые и элегантные функции, но это не гарантирует эффективность и высокую скорость исполнения.

Если рекурсия содержит баги (например, длится бесконечно), функции может не хватить памяти. Задать максимальное значение рекурсий можно с помощью модуля sys.

Глобальная переменная

Вот уже знакомый пример с глобальной переменной:

i = 0
def increment():
    global i
    i += 1

Здесь функция увеличивает на 1 значение глобальной переменной i. Это способ изменять глобальную переменную, определенную вне функции. Без него функция не будет знать, что такое переменная i. Ключевое слово global можно вводить в любом месте, но переменную разрешается использовать только после ее объявления.

За редкими исключениями глобальные переменные лучше вообще не использовать.

Присвоение функции переменной

С существующей функцией func синтаксис максимально простой:

variable = func

Переменным также можно присваивать встроенные функции. Таким образом позже есть возможность вызывать функцию другим именем. Такой подход называется непрямым вызовом функции.

Менять название переменной также разрешается:

def func(x): return x
a1 = func
a1(10)
10
a2 = a1
a2()
10

В этом примере a1, a2 и func имеют один и тот же id. Они ссылаются на один объект.

Практический пример — рефакторинг существующего кода. Например, есть функция sq, которая вычисляет квадрат значения:

def sq(x): return x*x

Позже ее можно переименовать, используя более осмысленное имя. Первый вариант — просто сменить имя. Проблема в том, что если в другом месте кода используется sq, то этот участок не будет работать. Лучше просто добавить следующее выражение:

square = sq

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

dir = 3

Теперь к ней нельзя получить доступ, а это может стать проблемой. Чтобы вернуть ее обратно, нужно просто удалить переменную:

del dir
dir()

Анонимная функция: лямбда

Лямбда-функция — это короткая однострочная функция, которой даже не нужно имя давать. Такие выражения содержат лишь одну инструкцию, поэтому, например, if, for и while использовать нельзя. Их также можно присваивать переменным:

product = lambda x,y: x*y

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

С помощью type() можно проверить тип:

>>> type(product)
function

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

power = lambda x=1, y=2: x**y
square = power
square(5.)
25
power = lambda x,y,pow=2: x**pow + y
[power(x,2, 3) for x in [0,1,2]]
[2, 3, 10]

Изменяемые аргументы по умолчанию

>>> def foo(x=[]):
...     x.append(1)
...     print x
...
>>> foo()
[1]
>>> foo()
[1, 1]
>>> foo()
[1, 1, 1]

Вместо этого нужно использовать значение «не указано» и заменить на изменяемый объект по умолчанию:

>>> def foo(x=None):
...     if x is None:
...         x = []
...     x.append(1)
...     print x
>>> foo()
[1]
>>> foo()
[1]

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

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

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

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

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

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

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

Объявление и вызов функций в 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. Регулярные выражения

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

Создание функции

Существуют некоторые правила для создания функций в Python.

  • Блок функции начинается с ключевого слова def, после которого следуют название функции и круглые скобки ( () ).
  • Любые аргументы, которые принимает функция должны находиться внутри этих скобок.
  • После скобок идет двоеточие ( : ) и с новой строки с отступом начинается тело функции.

Пример функции в Python:

def my_function(argument):
    print argument

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

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

Например:

my_function("abracadabra")

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

  • Обязательные аргументы (Required arguments)
  • Аргументы-ключевые слова (Keyword argument)
  • Аргументы по умолчанию (Default argument)
  • Аргументы произвольной длины (Variable-length argumens)

Обязательные аргументы функции:

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

Например:

def bigger(a,b):
    if a > b:
        print a
    else:
       print b

# В описании функции указано, что она принимает 2 аргумента

# Корректное использование функции
bigger(5,6)

# Некорректное использование функции
bigger()
bigger(3)
bigger(12,7,3) 

Аргументы — ключевые слова

Аргументы — ключевые слова используются при вызове функции. Благодаря ключевым аргументам, вы можете задавать произвольный (то есть не такой каким он описа при создании функции) порядок аргументов.

Например:

def person(name, age):
    print name, "is", age, "years old"

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

person(age=23, name="John")

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

Аргумент по умолчанию, это аргумент, значение для которого задано изначально, при создании функции.

Например:

def space(planet_name, center="Star"):
    print planet_name, "is orbiting a", center

# Можно вызвать функцию space так:
space("Mars")
# В результате получим: Mars is orbiting a Star

# Можно вызвать функцию space иначе:
space("Mars", "Black Hole")
# В результате получим: Mars is orbiting a Black Hole

Аргументы произвольной длины

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

Например:

def unknown(*args):
    for argument in args:
        print argument

unknown("hello","world") # напечатает оба слова, каждое с новой строки
unknown(1,2,3,4,5) # напечатает все числа, каждое с новой строки
unknown() # ничего не выведет

Ключевое слово return

Выражение return прекращает выполнение функции и возвращает указанное после выражения значение. Выражение return без аргументов это то же самое, что и выражение return None. Соответственно, теперь становится возможным, например, присваивать результат выполнения функции какой либо переменной.

Например:

def bigger(a,b):
    if a > b:
        return a # Если a больше чем b, то возвращаем a и прекращаем выполнение функции
    return b # Незачем использовать else. Если мы дошли до этой строки, то b, точно не меньше чем a

# присваиваем результат функции bigger переменной num
num = bigger(23,42)

Область видимости

Некоторые переменные скрипта могут быть недоступны некоторым областям программы. Все зависит от того, где вы объявили эти переменные.

В Python две базовых области видимости переменных:

  • Глобальные переменные
  • Локальные переменные

Переменные объявленные внутри тела функции имеют локальную область видимости, те что объявлены вне какой-либо функции имеют глобальную область видимости.

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

Например:

# глобальная переменная age
age = 44

def info():
    print age # Печатаем глобальную переменную age

def local_info():
    age = 22 # создаем локальную переменную age 
    print age

info() # напечатает 44
local_info() # напечатает 22

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

Например:

# глобальная переменная age
age = 13

# функция изменяющая глобальную переменную
def get_older():
    global age
    age += 1

print age # напечатает 13
get_older() # увеличиваем age на 1
print age # напечатает 14

Рекурсия

Рекурсией в программировании называется ситуация, в которой функция вызывает саму себя. Классическим примером рекурсии может послужить функция вычисления факториала числа.

Напомним, что факториалом числа, например, 5 является произведение всех натуральных (целых) чисел от 1 до 5. То есть, 1 * 2 * 3 * 4 * 5

Рекурсивная функция вычисления факториала на языке Python будет выглядеть так:

def fact(num):
    if num == 0: 
        return 1 # По договоренности факториал нуля равен единице
    else:
        return num * fact(num - 1) # возвращаем результат произведения num и результата возвращенного функцией fact(num - 1)

Однако следует помнить, что использование рекурсии часто может быть неоправданным. Дело в том, что в момент вызова функции в оперативной памяти компьютера резервируется определенное количество памяти, соответственно чем больше функций одновременно мы запускаем — тем больше памяти потребуется, что может привести к переполнению стека (stack overflow) и программа завершится аварийно, не так как предполагалось. Учитывая это, там где это возможно, вместо рекурсии лучше применять циклы.

Рецепт создания функции в Python

Существует следующий алгоритм — рекомендация по созданию функции в Python. Например, мы создаем функцию вычисления площади прямоугольника.

  1. Начинать следует с примеров того, что делает функция, и подобрать подходящее название. В нашем случае это будет выглядеть так:
    # На данном этапе мы еще не указываем имена переменных
    def rectangle_area_finder( ):
        """
        >>> rectangle_area_finder(3, 5)
        15
        >>> rectangle_area_finder(17.2, 6)
        103.2
        """
  2. Указать типы данных, которые принимает функция и тип данных, который она возвращает
    # функция принимает два числа, а возвращает одно
    def rectangle_area_finder( ):
        """
        (num, num) -> num    
    
        >>> rectangle_area_finder(3, 5)
        15
        >>> rectangle_area_finder(17.2, 6)
        103.2
        """
  3. Подобрать подходящие названия для переменных
    # Поскольку это математическая функция нам вполне подойдут имена a и b
    def rectangle_area_finder(a, b):
        """
        (num, num) -> num
        
        >>> rectangle_area_finder(3, 5)
        15
        >>> rectangle_area_finder(17.2, 6)
        103.2
        """
  4. Написать краткое, но содержательное описание функции
    def rectangle_area_finder(a, b):
        """
        (num, num) -> num
    
        Returns an area of a rectangle with given sides a and b.    
    
        >>> rectangle_area_finder(3, 5)
        15
        >>> rectangle_area_finder(17.2, 6)
        103.2
        """
  5. Написать собственно тело функции
    def rectangle_area_finder(a, b):
        """
        (num, num) -> num
    
        Returns an area of a rectangle with given sides a and b.    
    
        >>> rectangle_area_finder(3, 5)
        15
        >>> rectangle_area_finder(17.2, 6)
        103.2
        """
        return a * b
  6. Функция готова! Осталось вызвать ее с указанными в примерах аргументами

python function call example, пример вызова функции в Python

Как видно, при вызове команды help() с именем нашей функции в качестве аргумента мы получаем написанную нами документацию.

Сопровождайте ваши функции качественной документацией и программисты, которые будут работать с вашим кодом после вас будут вам благодарны.

Содержание:развернуть

  • Синтаксис
  • Термины и определения
  • Важность функций
  • Абстракция

  • Возможность повторного использования

  • Модульность

  • Пространство имен

  • Объявление и вызов функций
  • Область видимости функций
  • Локальная (L)

  • Область объемлющих функций (E)

  • Глобальная (G)

  • Аргументы
  • Позиционные

  • Именованные

  • Необязательные параметры (параметры по умолчанию)

  • Аргументы переменной длины (args, kwargs)

  • Передача по значению и по ссылке

  • Словарь в качестве аргументов (упаковка)

  • Возвращаемые значения (return)
  • Что можно возвращать

  • Распаковка возвращаемых значений

  • Пустая функция

  • Чистые функции и побочные эффекты
  • Lambda функции
  • Docstring
  • Аннотация типов
  • Функции vs процедуры — в чем отличие?
  • Время выполнения функции
  • Вложенные функции и рекурсия

Функция — это фрагмент программного кода, который решает какую-либо задачу.

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

Синтаксис

💁‍♀️ Простой пример: Вы торгуете мёдом, и после каждой продажи вам нужно печатать чек. В нём должно быть указано: название фирмы, дата продажи, список наименований проданных товаров, их количество, цены, общая сумма, а также сакраментальная фраза «Спасибо за покупку!».

Если не пользоваться функциями, всё придётся прописывать вручную. В простейшем случае программа будет выглядеть так:

print("ООО Медовый Гексагон")
print("Мёд липовый", end=" ")
print(1, end="шт ")
print(1250, end="р")
print("nCумма", 1250, end="р")
print("nСпасибо за покупку!")

А теперь представьте, что произойдёт, когда вы раскрутитесь, и покупатели станут приходить один за другим. В таком случае, чеки надо будет выдавать очень быстро. Но что делать, если вдруг нагрянет ваш любимый клиент и купит 10 сортов мёда в разных количествах? Далеко не все в очереди согласятся ждать, пока вы посчитаете общую сумму и внесёте её в чек.

Хорошо, что данный процесс можно легко оптимизировать с использованием функций.

def print_check(honey_positions):
sum = 0 # переменная для накопления общей суммы
print("ООО Медовый Гексагонn")
# в цикле будем выводить название, количество и цену
for honey in honey_positions:
name = honey[0]
amount = honey[1]
price = honey[2]
print(f"{name} ({amount} шт.) - {price} руб.")
sum += amount * price # здесь же будем считать ещё и общую сумму
print(f"nИтого: {sum} руб.")
print("Спасибо за покупку!")

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

# (название, количество, цена за штуку)
honey_positions = [
("Мёд липовый", 3, 1250),
("Мёд цветочный", 7, 1000),
("Мёд гречишный", 6, 1300),
("Донниковый мёд", 1, 1750),
("Малиновый мёд", 10, 2000),
]

Теперь этот список передадим в функцию как аргумент, и самостоятельно считать больше не придётся.

print_check(honey_positions)

>
ООО Медовый Гексагон

Мёд липовый (3 шт.) - 1250 руб.
Мёд цветочный (7 шт.) - 1000 руб.
Мёд гречишный (6 шт.) - 1300 руб.
Донниковый мёд (1 шт.) - 1750 руб.
Малиновый мёд (10 шт.) - 2000 руб.

Итого: 40300 руб.
Спасибо за покупку!

Да, код стал более массивным. Однако теперь для печати чека вам не придётся самостоятельно вычислять итог. Достаточно лишь изменить количество и цену товаров в списке. Существенная экономия времени! Слава функциям!

Термины и определения

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

# объявим функцию my_function()
def my_function():
# тело функции

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

  • Параметр — это переменная, которой будет присваиваться входящее в функцию значение.
  • Аргумент — само это значение, которое передается в функцию при её вызове.

Параметры и аргументы функции
# a, b - параметры функции
def test(a, b):
# do something

# 120, 404 — аргументы
test(120, 404)

Ключевая особенность функций — возможность возвращать значение

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

# она будет принимать два множителя, а возвращать их округленное
# до целого числа произведение
def int_multiple(a, b):
product = a * b
# возвращаем значение
return int(product)

print(int_multiple(341, 2.7))

> 920

☝️ Главная фишка возвращаемых значений в том, что их можно использовать в дальнейшем коде: присваивать переменным, совершать с ними разные операции и передавать как аргументы в другие функции.

# найдём квадратный корень из возврата функции int_multiple
# во встроенную функцию sqrt() мы передали вызов int_multiple
print(math.sqrt(int_multiple(44, 44)))

> 44

Важность функций

Абстракция

Человек бежит, машина едет, корабль плывёт, а самолёт летит. Всё это — объекты реального мира, которые выполняют однотипные действия. В данном случае, они перемещаются во времени и пространстве. Мы можем абстрагироваться от их природы, и рассматривать эти объекты с точки зрения того, какое расстояние они преодолели, и сколько времени на это ушло.

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

def calculate_speed(distance, time):
return distance / time

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

Возможность повторного использования

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

Например, при работе с массивами чисел, вам нужно часто их сортировать. Вместо того чтобы реализовать простой алгоритм сортировки (или использовать встроенную функцию), вам пришлось бы каждый раз перепечатывать тело этой или похожей функции:

# пузырьковая сортировка
def bubble_sort(nums):
for i in range(0, len(nums) - 1):
for j in range(len(nums) - 1):
if nums[j] > nums[j + 1]:
nums[j], nums[j + 1] = nums[j + 1], nums[j]
return nums

Всего 10 таких сортировок, и привет, лишние 50 строк кода.

Модульность

Разбитие больших и сложных процессов на простые составляющие — важная часть, как кодинга, так и реальной жизни. В повседневности мы занимаемся этим неосознанно. Когда убираемся в квартире, мы пылесосим, моем полы и окна, очищаем поверхности от пыли и наводим блеск на всё блестящее. Всё это — составляющие одного большого процесса под названием «уборка», но каждую из них также можно разбить на более простые подпроцессы.

В программировании модульность строится на использовании функций. Для каждой подзадачи — своя функция. Такая компоновка в разы улучшает читабельность кода и уменьшает сложность его дальнейшей поддержки.

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

Без применения модульности получится сплошная последовательность инструкций:

# Database operation program

# Код для чтения данных из базы
# ...
# ...

# Код для выполнения операций над данными
# ...
# ...

# Код для вывода результата
# ...
# ...

# Код для записи данных в базу
# ...
# ...

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

def read_from_db():
# Код для чтения данных из базы
# ...
# ...
# ...

def operate_with_data():
# Код для выполнения операций над данными
# ...
# ...
# ...

def print_result():
# Код для вывода результата
# ...
# ...
# ...

def write_to_db():
# Код для записи данных в базу
# ...
# ...
# ...

# код основной программы
# Database operation program
read_from_db()
operate_with_data()
print_result()
write_to_db()

Это и называется модульностью.

Пространство имен

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

💁‍♀️ Пример из жизни: в ВУЗе учатся два человека с совпадающими ФИО. Их нужно как-то различать. Если сделать пространствами имён группы этих студентов, то проблема будет решена. В рамках своей группы ФИО этих студентов будут уникальными.

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

Объявим функцию:

def hello():
print('Adele is cute')

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

# код выполняется последовательно, поэтому сейчас интерпретатор
# не знает о существовании функции hello
hello()

def hello():
print('Adele is cute')

> NameError: name 'hello' is not defined

Поэтому стоит лишь поменять объявление и вызов местами, и всё заработает:

def hello():
print('Adele is cute')

hello()
> Adele is cute

Область видимости функций

Рассмотрим подробнее области видимости:

Локальная (L)

Локальная область видимости находится внутри def:

def L():
# переменная i_am_local является локальной внутри L()
i_am_local = 5

Область объемлющих функций (E)

Объявили функцию e(). Внутри неё объявили функцию inner_e(). Относительно inner_e() все переменные, объявленные в e() будут относиться к области объемлющих функций. Такие переменные являются нелокальными в inner_e(). Чтобы с ними взаимодействовать, нужно использовать ключевое слово nonlocal:

def e():
x = 5

def inner_e():
nonlocal x
x = x + 1
return x

return inner_e()

print(e())
> 6

Глобальная (G)

Глобальная область видимости лежит за пределами всех def.

# G
num = 42

def some_function(n):
res = n + num
return res

print(some_function(1))
> 43

Аргументы

Позиционные

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

Значения в позиционных аргументах подставляются согласно позиции имён аргументов:

nums = [42, 11, 121, 13, 7]
state = True

# в данном примере
# 1-я позиция "nums" -> parameter_1
# 2-я позиция "state" -> parameter_2
def test_params(parameter_1, parameter_2):
pass

# равнозначные варианты вызова функции
test_params(nums, state)
test_params([42, 11, 121, 13, 7], True)

Именованные

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

def print_trio(a, b, c):
print(a, b, c)

print_trio(c=4, b=5, a=6)

> 6 5 4

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

Необязательные параметры (параметры по умолчанию)

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

def not_necessary_arg(x='My', y='love'):
print(x, y)

# если не передавать в функцию никаких значений, она отработает со значениями по умолчанию
not_necessary_arg()
> My love

# переданные значения заменяют собой значения по умолчанию
not_necessary_arg(2, 1)
> 2 1

Аргументы переменной длины (args, kwargs)

Когда заранее неизвестно, сколько конкретно аргументов будет передано в функцию, мы пользуемся аргументами переменной длины. Звёздочка «*» перед именем параметра сообщает интерпретатору о том, что количество позиционных аргументов будет переменным:

def infinity(*args):
print(args)

infinity(42, 12, 'test', [6, 5])
> (42, 12, 'test', [6, 5])

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

Функции в питоне могут также принимать и переменное количество именованных аргументов. В этом случае перед названием параметра ставится «**«:

def named_infinity(**kwargs):
print(kwargs)

named_infinity(first='nothing', second='else', third='matters')
> {'first': 'nothing', 'second': 'else', 'third': 'matters'}

Здесь kwargs уже заключает аргументы не в кортеж, а в словарь.

Передача по значению и по ссылке

В Python аргументы могут быть переданы, как по ссылке, так и по значению. Всё зависит от типа объекта.

Передача аргументов в функцию по значению (num) и по ссылке (my_list)

Если объект неизменяемый, то он передаётся в функцию по значению. Неизменяемые объекты это:

  • Числовые типы (int, float, complex).
  • Строки (str).
  • Кортежи (tuple).

num = 42

def some_function(n):
# в "n" передается значение переменной num (42)
n = n + 10
print(n)

some_function(num)
print(num) # "num" по прежнему содержит 42

>
52
42

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

В Python изменяемые объекты это:

  • Списки (list).
  • Множества (set).
  • Словари (dict).

num = [42, 43, 44]

def some_function(n):
# в "n" передается ссылка на переменную "num".
# "n" и "num" ссылаются на один и тот же объект
n[0] = 0
print(n)

some_function(num)
print(num) # "num" изменился

>
[0, 43, 44]
[0, 43, 44]

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

💭 В функциональном программировании существует понятие «функциями с побочными эффектами» — когда функция в процессе своей работы изменяет значения глобальных переменных. По возможности, избегать таких функций.

Словарь в качестве аргументов (упаковка)

Передаваемые в функцию аргументы можно упаковать в словарь при помощи оператора «**»:

def big_dict(**arguments):
print(arguments)

big_dict(key='value')
> {'key': 'value'}

Возвращаемые значения (return)

Что можно возвращать

Функции в Python способны возвращать любой тип объекта.

Распаковка возвращаемых значений

В Питоне поддерживается возврат функциями сразу несколько значений. Достаточно перечислить их через запятую после инструкции return. Возвращаемым типом будет кортеж (tuple), который можно распаковать в переменные.

def calculate(num1, num2):
return num1 + num2, num1 - num2, num1 * num2

# для так называемой распаковки нескольких значений
# их следует присвоить равному количеству аргументов
res1, res2, res3 = calculate(7, 6)

print(res1, res2, res3)
> 13 1 42

print(type(calculate(7, 6)))
<class 'tuple'>

☝️ Обратите внимание, что количество возвращаемых значение в кортеже должно совпадать с количеством переменных при распаковке. Иначе произойдет ошибка:

def calculate(num1, num2):
return num1 + num2, num1 - num2

# для так называемой распаковки нескольких значений
# их следует присвоить равному количеству аргументов
res1, res2, res3 = calculate(7, 6)

print(res1, res2, res3)

>
ValueError: not enough values to unpack (expected 3, got 2)

Пустая функция

Иногда разработчики оставляют реализацию на потом, и чтобы объявленная функция не генерировала ошибки из-за отсутствия тела, в качестве заглушки используется ключевое слово pass:

def empty():
pass

Чистые функции и побочные эффекты

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

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

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

Lambda функции

Кроме инструкции def в питоне можно создавать объекты функций в виде выражений. Так называемые анонимные функции создаются с помощью инструкции lambda. Чаще всего их применяют для получения встроенной функции или же для отложенного выполнения фрагмента программного кода.

lambda_test = lambda a, b: pow(a, b)

print(lambda_test(2, 4))
> 16

Docstring

Документировать код — особое искусство. Оно существует параллельно с разработкой и сопоставимо с ней по важности. Поэтому нередко документации в программе больше, чем самого кода.

Когда над проектом работает большая команда, а может и не одна, да и еще и много лёт подряд, то значение и важность документации возрастают прямо пропорционально.

Подробнее про docstring вы можете почитать тут:

Аннотация типов

Python — язык с динамической типизацией. По этой причине вполне возможны ситуации, когда вопреки ожиданиям разработчика в функцию подаются, например, не целые числа, а, допустим, строки. Чтобы отслеживать подобные случаи и сильнее контролировать процесс выполнения программы, была изобретена аннотация типов.

С помощью аннотации типов мы указываем, что параметры в функции имеют строго определенный тип.

def prod(a: int, b: int) -> int:
return a * b

В этой функции мы показали, что аргументы и результат должны быть целыми. Если передать float, то функция выполнится как обычно, однако IDE предупредит нас, что было получено неожиданное значение.

PyCharm предупреждает о передаче типа «str» вместо «int»

При этом интерпретатор считывает аннотации типов, но никак их не обрабатывает.

Функции vs процедуры — в чем отличие?

Для языка нет различий между функциями и процедурами. Но с точки зрения программиста — это разные сущности.

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

def proc(i, j):
pow(i, j)

proc(1, 200)

Она успешно отработает, но не вернёт нам результат. Поэтому добавляем ключевое слово return, и вот этот код обретает смысл:

def func(i, j):
return pow(i, j)

print(func(3, 2))
> 9

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

def print_low_word(word):
print(word.lower())
return 0

s = 'GOOD'
print_low_word(s)
> good

Возвращаемое значение не представляет собой никакой ценности, поэтому print_low_word(s) лучше оформить, как процедуру.

Время выполнения функции

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

from datetime import datetime
import time

start_time = datetime.now()
# здесь вызываем функцию
time.sleep(5)

print(datetime.now() - start_time)

Вложенные функции и рекурсия

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

def outerFunc():
def firstInner():
print('This is first inner function')

def secondInner():
print('This is second inner function')

firstInner()
secondInner()

outerFunc()
> This is first inner function
> This is second inner function

Рекурсия является частным случаем вложенной функции. Это функция, которая вызывает саму себя.

# посчитаем сумму чисел от 1 до num
def sum_from_one(num):
if num == 1:
return 1
return num + sum_from_one(num - 1)

print(sum_from_one(5))
> 15

😉

Все курсы > Программирование на Питоне > Занятие 6

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

функции в математике и программировании

Зачем это нужно? Если у вас есть код, который используется несколько раз в рамках программы, то функция позволяет написать код один раз, а потом просто вызывать его при необходимости. Так мы не дублируем код и лучше его структурируем.

Откроем ноутбук к этому занятию⧉

Встроенные функции

В Питоне есть множество встроенных в (1) стандартный функционал (built-in functions) и (2) дополнительные библиотеки (library functions) функций, и мы много раз их использовали.

Рассмотрим функцию для создания гистограммы plt.hist(). Вначале импортируем библиотеки.

import matplotlib.pyplot as plt

import numpy as np

Сгенерируем данные, которые передадим этой функции (эти же данные мы создавали и использовали на восьмом занятии вводного курса).

# установим точку отсчета для воспроизведения такого же результата

np.random.seed(42)

# и сгенерируем данные о росте

height = list(np.round(np.random.normal(180, 10, 1000)))

Теперь построим гистограмму передав ей в качестве параметров и аргументов наши данные и количество интервалов.

plt.hist(height, bins = 10)

plt.show()

параметры функции plt.hist()

Как мы видим, достаточно обратиться к соответствующей библиотеке (
plt), вызвать эту функцию по имени (
hist) и задать параметры и их аргументы (
heightи
bins = 10), и будет исполнен тот код, который заложили в нее создатели библиотеки Matplotlib.

Теперь несколько слов про параметры и аргументы функции.

Параметры и аргументы функции

Для начала определимся с терминами:

  • параметр — это то, что запрашивает функция при вызове (например,
    bins, количество интервалов)
  • аргумент — значение этого параметра (в нашем случае,
    10).

Возникает вопрос, что же такое
height? Логично предположить, что это аргумент (ведь это наши данные). Но тогда как функция узнает, какому параметру он соответствует?

Все дело в том, что параметры и их аргументы могут быть позиционными (positional) и именованными (keyword).

позиционные и именованные аргументы функции

В первом случае, достаточно указать аргумент и поставить его в правильном порядке (позиции). Функция сама поймет, какой параметр ей передают. Во втором случае, нужно указать и название параметра, и аргумент.

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

# данные в этой функции обозначаются через x

plt.hist(bins = 10, x = height)

plt.show()

использование именованных параметров функции plt.hist()

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

# у параметра bins есть аргумент по умолчанию (как раз 10 интервалов)

# а значит, этот параметр можно не указывать

plt.hist(height)

plt.show()

аргументы по умолчанию функции plt.hist()

Как вы видите, результат во всех трех случаях совершенно одинаковый.

Если вы сомневаетесь в том, какие параметры принимает функция и что является результатом ее работы, полезно обратиться к документации в Интернете. Например, по функции plt.hist() ее можно найти вот здесь⧉.

Стоит отметить, что функция может как принимать один, два или несколько параметров, так и не принимать их вовсе. Например, функция print(), если не указывать параметры, выдает пустую строку.

print(‘Первая строка’)

print()

print(‘Третья строка’)

Первая строка

Третья строка

Функции и методы

Некоторые функции называются методами. Методы — это функции, которые можно применить только к конкретному объекту. Другими словами, если обычная функция будет выполнена «сама по себе», это просто участок кода, которому дали имя, то методу для исполнения нужен объект (например, строка, список или словарь). При этом, что важно, у каждого объекта свои методы.

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

# создаем строковый объект и

some_string = ‘machine learning’

# применяем к нему метод .title()

some_string.title()

А теперь попробуем применить этот метод к списку, состоящему из тех же слов, что и строка.

some_list = [‘machine’, ‘learning’]

some_list.title()

ошибка при применении строкового метода .title() к списку

Как мы видим, Питон выдал ошибку.

Собственные функции в Питоне

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

Функции не обязательно должны быть встроены в базовый функционал или библиотеки. Мы вполне можем объявлять (т.е. создавать) собственные функции (user-defined functions). Рассмотрим пример.

# создадим функцию, которая удваивает

# любое передаваемое ей значение

def double(x):

  res = x * 2

  return res

# и вызовем ее, передав число 2

double(2)

Теперь давайте разберем каждый элемент этого кода. Вначале посмотрим как объявить функцию (declare a function).

синтаксис собственной функции

  • ключевое слово def необходимо для объявления функции
  • далее идут название функции, которое вы сами определяете, и
  • параметры, которые может принимать ваша функция
  • после двоеточия на новой строке с отступом идет так называемое тело функции, то есть то, что будет исполняться при вызове функции
  • в конце ставится ключевое слово return, возвращающее результат работы функции

Затем, когда это необходимо, мы можем вызвать функцию (call a function), указав ее имя и передав, при их наличии, соответствующие аргументы внутри круглых скобок.

вызов собственной функции

Пустое тело функции

Оставлять тело функции совсем пустым нельзя. Нужно как минимум указать ключевое слово return или оператор pass.

# тело функции не может быть пустым

def only_return():

  # нужно либо указать ключевое слово return

  return

# либо оператор pass

def only_pass():

  pass

Хотя может показаться, что в этом случае функция ничего не выдает, на самом деле это не так. И в том, и в другом случае функция возвращает особый тип данных None (отсутствие значения).

Функция print() вместо return

Помимо ключевого слова return, результат работы функции можно вывести с помощью print().

def double_print(x):

  res = x * 2

  print(res)

Хотя визуально вывод идентичен, отличие все-таки есть:

  • Использование return возвращает значение функции (в нашем случае значение переменной res) и прерывает ее работу
  • Функция print() просто выводит это значение пользователю и не влияет на дальнейшее исполнение кода, если он есть

Параметры собственных функций

С точки зрения параметров, у собственных функций те же самые возможности, что и у встроенных функций. В частности, параметры могут быть позиционными и именованными.

# объявим функцию с параметрами x и y,

def calc_sum(x, y):

  # которая возвращает их сумму

  return x + y

# вызовем эту функцию с одним позиционным и одним именованным параметром

calc_sum(1, y = 2)

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

def calc_sum_default(x = 1, y = 2):

  return x + y

calc_sum_default()

И конечно функция может изначально не иметь параметров.

# эта функция просто выводит текст ‘Some string’

def print_string():

  print(‘Some string’)

print_string()

Аннотация функции

Аннотация функции (function annotation) позволяет явно прописать тип данных параметров (parameter annotation) и возвращаемых значений (return annotation).

# укажем, что на входе функция принимает тип float, а возвращает int

# значение 3,5 — это значение параметра x по умолчанию

def f(x: float = 3.5) -> int:

  return int(x)

# желаемый тип данных можно посмотреть через атрибут __annotations__

f.__annotations__

{‘return’: int, ‘x’: float}

# вызовем функцию без параметров

f()

Аннотация не является обязательной и никак не вляет на выполнение кода.

# сохраним аннотации, но изменим суть функции

def f(x: float) -> int:

  # теперь вместо int она будет возвращать float

  return float(x)

# вновь вызовем функцию, передав ей на входе int, и ожидая на выходе получить float

f(3)

Дополнительные возможности функций

Вызов функции можно совмещать с арифметическими операциями.

# вызовем объявленную выше функцию и умножим ее вывод на два

calc_sum(1, 2) * 2

Доступны и логические операции.

Если результатом вывода является строка, то у этой строки также есть индекс.

def first_letter():

  return ‘Python’

# обратимся к первой букве слова Python

first_letter()[0]

Функция может не использовать параметры, но получать данные от пользователя через input().

def use_input():

  # запросим у пользователя число и переведем его в тип данных int

  user_inp = int(input(‘Введите число: ‘))

  # возведем число в квадрат

  result = user_inp ** 2

  # вернем результат

  return result

# вызовем функцию

use_input()

Появится окно для ввода числа.

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

Введем число пять и посмотрим на результат.

Результат вызова функции

Функция не обязательно возвращает только число или строку, это может быть, в частности, список, кортеж или словарь. Рассмотрим несколько примеров.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

# объявим функцию, которая на входе получает число,

# а на выходе формирует список чисел от 0 до числа,

# предшествующего заданному

def create_list(x):

  # создадим пустой список

  l = []

  # в цикле for создадим последовательность

  for i in range(x):

    # и поместим ее в список

    l.append(i)

  return l

# результатом вызова этой функции будет список

create_list(5)

Функция может возвращать сразу несколько значений.

def tuple_f():

  string = ‘Python’

  x = 42

  return string, x

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

a, b = tuple_f()

print(a, b)

print(type(a), type(b))

Python 42

<class ‘str’> <class ‘int’>

Если записать в одну, то получится кортеж.

c = tuple_f()

print(c)

print(type(c))

(‘Python’, 42)

<class ‘tuple’>

Функция может возвращать и логическое значение. Давайте объявим функцию, которая проверяет четное ли ей передали число (и в этом случае вернет True) или нечетное (и тогда False).

# проверим равен ли нулю остаток от деления на два

def if_divisible(x):

  if x % 2 == 0:

    return True

  else:

    return False

# попробуем с числом 10

if_divisible(10)

Использование библиотек

Внутри функций можно использовать дополнительные библиотеки Питона. Например, применим функцию mean() библиотеки Numpy для расчета среднего арифметического.

# на входе функция примет список или массив x,

def mean_f(x):

  # рассчитает среднее арифметическое и прибавит единицу

  return np.mean(x) + 1

# перед вызовом функции нужно не забыть импортировать соответствующую библиотеку

import numpy as np

# и подготовить данные

x = [1, 2, 3]

mean_f(x)

Глобальные и локальные переменные

Некоторые переменные существуют (или как еще говорят, видны) только внутри функции, другие во всей программе. В первом случае, говорят про локальные переменные, во втором — про глобальные. Сразу приведем несложный пример.

# создадим глобальную переменную ВНЕ функции

global_name = ‘Петр’

# а затем используем ее внутри новой функции

def show_name():

  print(global_name)

Здесь никаких проблем не возникло. Мы создали глобальную переменную и потом легко использовали ее внутри очередной функции. Обратное не всегда возможно.

# а теперь вначале создадим функцию,

# внутри которой объявим локальную переменную

def show_local_name():

  local_name = ‘Алена’

  print(local_name)

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

ошибка при вызове локальной переменной вне своей функции

Все дело в том, что область видимости этой переменной ограничена функцией show_local_name(). Для того чтобы она была видна во всей программе, можно использовать ключевое слово global.

def make_global():

  global local_name

  local_name = ‘Алена’

  print(local_name)

# теперь ошибки быть не должно

local_name

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

# объявим глобальную переменную

global_number = 5

def print_number():

  # затем объявим локальную переменную

  local_number = 10

  print(‘Local number:’, local_number)

Функция всегда «предпочтет» содержащуюся в ней локальную переменную.

При этом значение глобальной переменной для остального кода не изменится.

print(‘Global number:’, global_number)

Анонимные или lambda-функции

Функции создают не только через ключевое слово def и название функции. Можно использовать слово lambda и вообще обойтись без названия. Приведем простой пример.

# создадим функцию, которая принимает два числа и перемножает их

lf = lambda a, b: a * b

# вызовем функцию и передадим ей числа 2 и 3

lf(2, 3)

Теперь давайте в деталях рассмотрим, как мы получили такой результат.

синтаксис lambda-функции

  • вначале ставится ключевое слово lambda
  • за ним идут передаваемые параметры
  • через двоеточие пишется исполняемое выражение

Разумеется, ничто не мешает поместить этот же функционал в обычную функцию.

def normal_f(a, b):

  return a * b

normal_f(2, 3)

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

Lambda-функция внутри функции filter()

Предположим, у нас есть список чисел, и мы хотим оставить в нем только те числа, которые больше 10. Давайте решим эту задачу с помощью функции filter() и lambda-функции.

Функция filter() принимает два параметра:

  • Во-первых, еще одну функцию, выполняющую роль критерия; она выдает
    True, если элемент нужно оставить, и
    False — если убрать
  • Во-вторых, набор элементов, которые нужно отфильтровать в виде списка, кортежа или множества

Получив их, filter() применяет критерий (функцию) к каждому из элементов набора.

Посмотрим на реализацию на Питоне. Вначале создадим список.

nums = [15, 27, 9, 18, 3, 1, 4]

Теперь зададим фильтрующую lambda-функцию.

# буквально мы пишем, для каждого n,

# выдай True, если число больше 10, иначе — False

criterion = lambda n: True if (n > 10) else False

После этого поместим criterion и nums в функцию filter(). Так как сама функция filter() вернет нам не список, а специальный объект iterator, его в свою очередь нужно преобразовать обратно в список с помощью функции list().

list(filter(criterion, nums))

Чаще такой функционал записывают в одну строчку.

list(filter(lambda n: True if (n > 10) else False, nums))

И в этом и заключается удобство lambda-функции, ее не надо объявлять заранее. Через обычную функцию код выглядел бы так.

def criterion_2(n):

  if n > 10:

    return True

  else:

    return False

list(filter(criterion_2, nums))

Lambda-функция внутри функции sorted()

Теперь рассмотрим lambda-функцию в коде, который мы использовали на занятии по рекомендательным системам. Воспроизведем в миниатюре часть решения из того занятия.

В какой-то момент мы получили список из кортежей. И в каждом кортеже был индекс фильма и расстояние до него.

list_of_tuples = [(901, 0.0), (1002, 0.22982440568634488), (442, 0.25401128310081567)]

Затем мы захотели отсортировать этот список по расстоянию, то есть по второму элементу кортежа.

Мы взяли функцию sorted() и в качестве параметра ключа, по которому сортировать список (key), передали ей lambda-функцию, принимающей кортеж из двух элементов на входе, и выдающей второй его элемент на выходе.

sorted(indices_distances, key = lambda x: x[1], reverse = True)

[(442, 0.25401128310081567), (1002, 0.22982440568634488), (901, 0.0)]

Параметр
reverse = True, напомню, задает сортировку по убыванию.

Немедленно вызываемые функции

Lambda-функции относятся к так называемым немедленно вызываемым функциям или immediately invoked function expressions (IIFE). Это означает, что мы можем одновременно объявить и вызвать такую функцию.

# обратите внимание на использование скобок

(lambda x: x * x)(10)

*args и **kwargs

Прежде чем завершить, поговорим про еще одну важную тему, а именно про так называемые *args (сокращение от arguments) и **kwargs (keyword arguments).

Они позволяют передавать функции различное количество позиционных (*args) или именованных (**kwargs) аргументов.

Рассмотрим на примере. Начнем с *args.

*args

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

# объявим функцию

def mean(a, b):

  return (a + b) / 2

# и передадим ей числа 1 и 2

mean(1, 2)

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

# объявим функцию, которой нужно передать список

def mean(list_):

  # зададим переменную для суммы,

  total = 0

  # в цикле сложим все числа из списка

  for i in list_:

    total += i

  # и разделим на количество элементов

  return total / len(list_)

# создадим список

list_ = [1, 2, 3, 4]

# и передадим его в новую функцию

mean(list_)

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

ошибка при использовании *args

*args позволяет передавать функции произвольное количество отдельных чисел.

# объявим функцию с *args

def mean(*nums):

  total = 0

  for i in nums:

    total += i

  return total / len(nums)

Как вы видите, главным элементом здесь является оператор распаковки * (unpacking operator). Он принимает все передаваемые в функцию числа и формирует из них кортеж.

Затем мы проходимся по элементам этого кортежа, рассчитываем их сумму и делим на количество элементов. Использовать слово args не обязательно, мы назвали наш позиционный аргумент nums.

Если мы по какой-то причине захотим передать функции список, мы можем это сделать.

# передадим в функцию список

mean(*list_)

В этом случае мы передаем название списка со звездочкой *.

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

def test_type(*nums):

  print(nums, type(nums))

(1, 2, 3, 4) <class ‘tuple’>

**kwargs

При использовании **kwargs происходит почти то же самое за тем исключением, что мы распаковываем именованные, а не позиционные аргументы. И распаковываем их в словарь, а не в список. Сразу посмотрим на примере.

def f(**kwargs):

  return kwargs.items()

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

# и внутри функции сформирует из них словарь

f(a = 1, b = 2)

dict_items([(‘a’, 1), (‘b’, 2)])

Приведем более сложный пример. Напишем функцию, которая на вход примет произвольное количество чисел (позиционный аргумент), преобразует в кортеж (*args) и рассчитает среднее арифметическое (mean) и среднее квадратическое отклонение (standard deviation).

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

# nums функция преобразует в кортеж, params — в словарь

def simple_stats(*nums, **params):

  # если ключ ‘mean’ есть в словаре params и его значение == True

  if ‘mean’ in params and params[‘mean’] == True:

    # рассчитаем среднее арифметическое кортежа nums и округлим

    # t — это символ табуляции

    print(f‘mean: t{np.round(np.mean(nums), 3)}’)

  # если ключ ‘std’ есть в словаре params и его значение == True

  if ‘std’ in params and params[‘std’] == True:

    # рассчитаем СКО кортежа nums и округлим

    print(f‘std: t{np.round(np.std(nums), 3)}’)

Вызовем функцию simple_stats() и передадим ей числа и именованные аргументы.

simple_stats(5, 10, 15, 20, mean = True, std = True)

Если для одного из параметров задать значение False, функция не выведет соответствующую метрику.

simple_stats(5, 10, 15, 20, mean = True, std = False)

Для того чтобы передать параметры списком и словарем, нам нужно использовать операторы распаковки
* и
** соответственно.

list_ = [5, 10, 15, 20]

settings = {‘mean’ : True, ‘std’ : True}

simple_stats(*list_, **settings)

Количество именованных аргументов в **kwargs может быть любым. Ничто не мешает нам добавить еще один параметр.

# добавим параметр median

simple_stats(5, 10, 15, 20, mean = True, std = True, median = True)

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

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

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

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

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

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

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

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

Вопросы для закрепления

Какие три вида функций мы изучили?

Посмотреть правильный ответ

Ответ: встроенные, собственные, а также анонимные или lambda-функции.

Какие бывают параметры и аргументы функции?

Посмотреть правильный ответ

Ответ: позиционные (в этом случае мы указываем только аргумент, но ставим его в определенном порядке) и именованные (указываем и параметр, и аргумент, но порядок не важен).

Какова область видимости локальной переменной?

Посмотреть правильный ответ

Ответ: область видимости локальной переменной ограничена той функцией, в которой эта переменная была объявлена.

В ноутбуке к лекции приведены дополнительные упражнения⧉.

В следующий раз мы подробнее рассмотрим списки, кортежи и множества.


Ответы на вопросы

Вопрос. Скажите, а почему используется символ нижнего подчеркивания в названии переменной list_?

Ответ. Не стоит использовать просто list для именования переменных, потому что это слово зарезервировано для названия функции. Аналогично не стоит использовать dict, tuple, set и т.д. При этом некоторые слова использовать в качестве названия переменных просто не получится. Питон выдаст ошибку. Это, например, if, for, True, False, import и т.п.

Символ подчеркивания является одним из вариантов решения.

Назад в начало

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

Функция позволяет использо­вать в про­грамме один и тот же фрагмент кода нес­колько раз.

Oбъявление функции в Python выглядит так:

def function_name(argument1, argument2, …):

    # код функции

# def — DEclare Function — «объявить функцию»

# function_name — имя функции

# (argument1, argument2, …) — список аргументов, поступающих на вход функции при ее вызове

# тело функции — это весь код, который идет после двоеточия

# Объявление функции


def hello(name):

    print(‘Hello, ‘ + name)

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


hello(‘Max’)

hello(‘Ivan’)

hello(‘Alex’)

hello(‘Kate’)

# Вывод


>> Hello, Max

>> Hello, Ivan

>> Hello, Alex

>> Hello, Kate

Оператор return возвращает значение из функции.

Представьте себе обычный калькулятор. Вы вводите первое число, операцию и второе число. Калькулятор возвращает нам результат операции над этими числами. Всё просто, не так ли? Функции точно так же умеют возвращать значение с помощью специального оператора return.

# Объявление функции


def sum2(a, b):

    return a + b

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


s1 = sum2(10, 2)

s2 = sum2(108, 100)

s3 = sum2(3, 1)

print(f‘s1 = {s1})

print(f‘s2 = {s2})

print(f‘s3 = {s3})

>> s1 = 12

>> s2 = 208

>> s3 = 4

# Функция умножения двух чисел


def mult2(a, b):

    return a * b

# Вызовем нашу функцию


m1 = mult2(10, 2)

m2 = mult2(108, 100)

m3 = mult2(3, 1)

print(f‘m1 = {m1})

print(f‘m2 = {m2})

print(f‘m3 = {m3})

>> m1 = 20

>> m2 = 10800

>> m3 = 3

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

# Аргумент name по умолчанию равен ‘world’


def hello(name=‘world’):

    print(‘Hello, ‘ + name)

hello()

hello(‘Ivan’)

>> Hello, world

>> Hello, Ivan

Примеры

1. Квадрат

# Написать функцию square(), вычисляющую квадрат числа.


def square(number):

    return number * number # Возвращаем результат работы функции обратно в программу


a = square(2)

print(a)

>> 4

2. Периметр

# Напишите функцию perimetr, вычисляющую периметр прямоугольника со сторонами a и b.


def perimetr(a, b):

    return 2 * (a + b)

p = perimetr(4, 3)

print(p)

>> 14

3. Четное число

# Напишите функцию isEven, возвращающую True, если число четное, и False, если — нечетное.


def isEven(x):

    return x % 2 == 0

print(isEven(10))

print(isEven(11))

>> True

>> False

4. Сумма списка

# Напишите функцию amountList, которая возвращает сумму всех элементов списка.


def amountList(lst):

    amount = 0

    for x in lst:

        amount += x

    return amount

print(amountList([1, 2, 3]))

mylist = [1, 2, 4, 8, 16]

s = amountList(mylist)

print(f‘Сумма списка {mylist} равна {s})

>> 6

>> Сумма списка [1, 2, 4, 8, 16] равна 31

5. Фибоначчи

# Напишите функцию fib, которая возвращает n-ное число Фибоначчи.

# Последовательность Фибоначчи выглядит так: 1 1 2 3 5 8 13 21 34


def fib(n):

    a, b = 0, 1

    if n == 0: return 0

    for i in range(1, n):

        a, b = b, a + b

    return b

print(fib(2))

print(fib(3))

print(fib(4))

print(fib(5))

print(fib(10))

>> 1

>> 2

>> 3

>> 5

>> 55

6. Факториал

# Напишите функцию fact, вычисляющую значение факториала числа N.

# Факториал числа — это произведение всех чисел от 1 до N.

# Например, факториал числа 5 равен 120 (5! = 120).


def fact(n):

    result = 1

    while n > 1:

        result *= n

        n -= 1

    return result

print(fact(2))

print(fact(3))

print(fact(4))

print(fact(5))

>> 2

>> 6

>> 24

>> 120

Решение задач

1. Площадь круга

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

# Не забудьте написать функцию circle…


print(circle(4))

print(circle(1))

# Вывод:

>> 50.24

>> 3.14

2. На три

Напишите функцию, которая возвращает True, если число делится на 3, и False, если — нет.

# Не забудьте написать функцию three…


print(three(4))

print(three(3))

# Вывод:

>> False

>> True

3. Максимум в списке

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

# Напишите функцию maxList…

mylist = [1, 3, 2]

print(maxList(mylist))

# Вывод:

>> 3

4. Сколько четных

Напишите функцию, которая возвращает количество четных элементов в списке.

# Напишите функцию evenCounter…

mylist = [1, 10, 2, 4, 6]

evens = evenCounter(mylist)

print(even)

# Вывод:

>> 4

5. Уникальные

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

# Напишите функцию unique…

mylist = [1, 1, 2, 1, 3, 2, 3]

print(unique(mylist))

# Вывод:

>> [1, 2, 3]

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

Функции в Python – это организованный блок многократно используемого кода, который можно вызывать при необходимости.

Функция содержит набор программных операторов, заключенных в {}. Функцию можно вызывать несколько раз, чтобы обеспечить возможность повторного использования и модульность программы Python.

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

Python предоставляет нам различные встроенные функции, такие как range() или print(). Пользователь также может создавать свои функции, которые можно назвать пользовательскими функциями.

В основном есть два типа функций:

  • Функции, определяемые пользователем. Определяются пользователем для выполнения конкретной задачи.
  • Встроенные функции. Это те функции, которые предварительно определены в Python.

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

Преимущество функций в Python

У функций Python есть следующие преимущества:

  • Используя функции, мы можем избежать повторной перезаписи одной и той же логики / кода снова и снова в программе.
  • Мы можем вызывать функции Python несколько раз и в любом месте программы.
  • Мы можем легко отслеживать большую программу Python, если она разделена на несколько функций.
  • Возможность повторного использования – главное достижение.
  • Однако вызов функции всегда является накладным.

Создание

Python предоставляет ключевое слово def для определения функции. Синтаксис функции определения приведен ниже.

Синтаксис:

def my_function(parameters):
      function_block
return expression

Давайте разберемся с синтаксисом определения функций.

  • Ключевое слово def вместе с именем функции используется для определения функции.
  • Правило идентификатора должно следовать за именем функции.
  • Функция принимает параметр(аргумент), и они могут быть необязательными.
  • Функциональный блок начинается с двоеточия(:), и операторы блока должны иметь такой же отступ.
  • Оператор return используется для возврата значения. Функция может иметь только один возврат.

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

В Python после создания функции мы можем вызывать ее из другой функции. Перед вызовом функция должна быть определена; в противном случае интерпретатор Python выдает ошибку. Чтобы вызвать функцию, используйте имя функции, за которым следуют круглые скобки.

Рассмотрим простой пример, который выводит сообщение «Hello World».

#function definition
def hello_world():  
    print("hello world")  
# function calling
hello_world()    

Выход:
hello world

Оператор возврата return

Оператор return используется в конце функции и возвращает результат функции. Он завершает выполнение функции и передает результат туда, где функция вызывается. Оператор return не может использоваться вне функции.

Синтаксис:

return [expression_list]

Он может содержать выражение, которое оценивается, и значение возвращается вызывающей функции. Если оператор return не имеет выражения или не существует сам по себе в функции, он возвращает объект None.

Рассмотрим следующие примеры:

Пример 1.

# Defining function
def sum():
    a = 10
    b = 20
    c = a+b
    return c
# calling sum() function in print statement
print("The sum is:",sum())

Выход:
The sum is: 30

В приведенном выше коде мы определили функцию с именем sum, и у нее есть оператор c = a + b, который вычисляет заданные значения, а результат возвращается оператором return вызывающей функции.

Пример 2. Создание функции без оператора возврата

# Defining function
def sum():
    a = 10
    b = 20
    c = a+b
# calling sum() function in print statement
print(sum())

Выход:

None

В приведенном выше коде мы определили ту же функцию без оператора return, так как мы видим, что функция sum() вернула объект None вызывающей функции.

Аргументы в функции

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

Рассмотрим следующие примеры, содержащий функцию, которая принимает строку в качестве аргумента.

Пример 1.

#defining the function  
def func(name):  
    print("Hi ",name) 
#calling the function   
func("Devansh")   

Выход:

Hi Devansh

Пример 2.

#Python function to calculate the sum of two variables   
#defining the function  
def sum(a,b):  
    return a+b;  
  
#taking values from the user  
a = int(input("Enter a: "))  
b = int(input("Enter b: "))  
  
#printing the sum of a and b  
print("Sum = ",sum(a,b))  

Выход:

Enter a: 10
Enter b: 20
Sum =  30

Вызов по ссылке в Python

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

Пример 1. Передача неизменяемого объекта(списка)

#defining the function  
def change_list(list1):  
    list1.append(20) 
    list1.append(30)  
    print("list inside function = ",list1)  
  
#defining the list  
list1 = [10,30,40,50]  
  
#calling the function   
change_list(list1)
print("list outside function = ",list1)

Выход:
list inside function = [10, 30, 40, 50, 20, 30]
list outside function = [10, 30, 40, 50, 20, 30]

Пример 2. Передача изменяемого объекта(строки)

#defining the function  
def change_string(str):  
    str = str + " Hows you "
    print("печать строки внутри функции :",str) string1 = "Hi I am there" #calling the function change_string(string1) print("печать строки вне функции :",string1)

Выход:
печать строки внутри функции: Hi I am there Hows you
печать строки вне функции: Hi I am there.

Типы аргументов

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

  1. Обязательные аргументы.
  2. Аргументы ключевого слова.
  3. По умолчанию.
  4. Переменной длины.

Обязательные

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

Рассмотрим следующие примеры.

Пример 1.

def func(name):  
    message = "Hi "+name
    return message
name = input("Enter the name:")  
print(func(name))  

Выход:
Введите имя: Джон
привет, Джон

Пример 2.

#the function simple_interest accepts three arguments and returns the simple interest accordingly  
def simple_interest(p,t,r):  
    return(p*t*r)/100  
p = float(input("Enter the principle amount? "))  
r = float(input("Enter the rate of interest? "))  
t = float(input("Enter the time in years? "))  
print("Simple Interest: ",simple_interest(p,r,t))  

Выход:
Введите основную сумму: 5000
Введите процентную ставку: 5
Введите время в годах: 3
Простой процент: 750,0

Пример 3

#the function calculate returns the sum of two arguments a and b  
def calculate(a,b):  
    return a+b  
calculate(10) # this causes an error as we are missing a required arguments b.  

Выход:
TypeError: calculate() отсутствует 1 обязательный позиционный аргумент: 'b'

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

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

Пример 1.

def printme(name,age=22):  
    print("My name is",name,"and age is",age)  
printme(name = "john")

Выход:
My name is John and age is 22
Пример 2.

def printme(name,age=22):  
    print("My name is",name,"and age is",age)  
printme(name = "john") #the variable age is not passed into the function however the default value of age is considered in the function  
printme(age = 10,name="David") #the value of age is overwritten here, 10 will be printed as age 

Выход:
My name is john and age is 22
My name is David and age is 10

Аргументы переменной длины(* args)

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

Однако при определении функции мы определяем аргумент переменной длины, используя * args(звездочку) как * <переменная – имя>.

Рассмотрим следующий пример:

def printme(*names):  
    print("type of passed argument is ",type(names))  
    print("printing the passed arguments...")  
    for name in names:  
        print(name)  
printme("john","David","smith","nick")  

Выход:
type of passed argument is <class 'tuple'>
printing the passed arguments...
john
David
smith
nick

В приведенном выше коде мы передали * имена в качестве аргумента переменной длины. Мы вызвали функцию и передали значения, которые внутри обрабатываются как кортежи. Кортеж – это итеративная последовательность, такая же, как и список. Чтобы напечатать заданные значения, мы повторили имена * arg, используя цикл for в Python.

Аргументы ключевого слова(** kwargs)

Python позволяет нам вызывать функцию с аргументами ключевых слов. Такой вызов функции позволит нам передавать аргументы в случайном порядке.

Имя аргументов рассматривается как ключевое слово и сопоставляется при вызове и определении функции. Если такое же совпадение найдено, значения аргументов копируются в определение функции.

Рассмотрим следующие примеры.

Пример 1.

#function func is called with the name and message as the keyword arguments  
def func(name,message):  
    print("printing the message with",name,"and ",message)  
    
    #name and message is copied with the values John and hello respectively  
    func(name = "John",message="hello") 

Выход:
printing the message with John and hello

Пример 2. С указанием значений в другом порядке при вызове.

#The function simple_interest(p, t, r) is called with the keyword arguments the order of arguments doesn't matter in this case  
def simple_interest(p,t,r):  
    return(p*t*r)/100  
print("Simple Interest: ",simple_interest(t=10,r=10,p=1900))   

Выход:
Simple Interest: 1900.0
Если мы предоставим другое имя аргументов во время вызова функции, будет выдана ошибка.

Рассмотрим следующий пример.

Пример 3.

#The function simple_interest(p, t, r) is called with the keyword arguments.   
def simple_interest(p,t,r):  
    return(p*t*r)/100  

# doesn't find the exact match of the name of the arguments(keywords)    
print("Simple Interest: ",simple_interest(time=10,rate=10,principle=1900)) 

Выход:
TypeError: simple_interest() got an unexpected keyword argument 'time'

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

Рассмотрим следующие примеры.

Пример 4.

def func(name1,message,name2):  
    print("printing the message with",name1,",",message,",and",name2)  
#the first argument is not the keyword argument  
func("John",message="hello",name2="David") 

Выход:
printing the message with John , hello ,and David

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

Пример 5.

def func(name1,message,name2): 
    print("printing the message with",name1,",",message,",and",name2)  
func("John",message="hello","David")      

Выход:
SyntaxError: positional argument follows keyword argument

Python предоставляет возможность передавать несколько аргументов ключевого слова, которые могут быть представлены как ** kwargs. Похож на * args, но сохраняет аргумент в формате словаря. Этот тип аргументов полезен, когда мы не знаем заранее количество аргументов.

Рассмотрим следующий пример:

Пример 6. Многие аргументы используют аргумент ключевого слова.

def food(**kwargs):
    print(kwargs)
food(a="Apple")
food(fruits="Orange", Vagitables="Carrot")

Выход:

{'a': 'Apple'}
{'fruits': 'Orange', 'Vagitables': 'Carrot'}

Объем переменных

Объем переменных зависит от места, где переменная объявляется. Переменная, объявленная в одной части программы, может быть недоступна для других частей.

В Python переменные определяются с двумя типами областей видимости:

  1. Глобальны.
  2. Локальные.

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

Рассмотрим следующий пример.

Пример 1. Локальная переменная

def print_message():  
    message = "hello !! I am going to print a message." # the variable message is local to the function itself  
    print(message)  
print_message()  
print(message) # this will cause an error since a local variable cannot be accessible here.    

Выход:
hello !! I am going to print a message.
File "/root/PycharmProjects/PythonTest/Test1.py", line 5, in
print(message)
NameError: name 'message' is not defined

Пример 2. Глобальная переменная

def calculate(*args):  
    sum=0  
    for arg in args:  
        sum = sum +arg  
    print("The sum is",sum)  
sum=0  
calculate(10,20,30) #60 will be printed as the sum  
print("Value of sum outside the function:",sum) # 0 will be printed  Output:

Выход:
The sum is 60
Value of sum outside the function: 0

Изучаю Python вместе с вами, читаю, собираю и записываю информацию опытных программистов.

Понравилась статья? Поделить с друзьями:
  • Как написать функциональные требования
  • Как написать функциональное резюме
  • Как написать фугу для чайников
  • Как написать фолк метал
  • Как написать фнаф