Вторая часть функций в Python (совсем базу вряд-ли буду выкладывать). Типы аргументов, некоторые встроенные и lambda функции
Необязательные и именованные аргументы
Позиционные аргументы
Когда мы вызываем функции c позиционными аргументами, значения в них подставляются согласно позиции их имен в определении функции. Например код ниже выведет число 7. При вызове функции diff() первому параметру x будет соответствовать первый переданный аргумент – 10, а второму параметру y – второй аргумент – 3.
Аргументы, передаваемые с именами, называются именованными. Чтобы передать именованные аргументы в функцию, нужно указать их имена, которые были заданы при объявлении функции:
При вызове функции меняется порядок передаваемых аргументов. Когда функции назначаются соответствующие значения именованных аргументов, Python учитывает их имена, а не позиции. В результате функция будет всегда выводить одно и то же значение независимо от позиций переданных ей аргументов.
Совет
Рекомендация по тому, когда стоит использовать именованные аргументы: если функция принимает больше трёх аргументов, нужно хотя бы часть из них указать по имени.
1
2
3
4
defmake_circle(x,y,radius,line_width,fill):# тело функцииmake_circle(x=200,y=300,radius=17,line_width=2.5,fill=True)
Предупреждение
Мы можем вызывать функции, используя именованные и позиционные аргументы одновременно. Но позиционные значения должны быть указаны до любых именованных!
Необязательные аргументы
Бывает, что какой-то параметр функции часто принимает одно и то же значение. Например, для функции print() установили значения параметров sep и end равными символу пробела и символу перевода строки, поскольку эти значения используют наиболее часто. Другим примером служит функция int(), преобразующая строку в число. Она принимает два аргумента: первый аргумент – строка, которую нужно преобразовать в число, второй аргумент – основание системы счисления, значение по умолчанию которого равно 10.
Чтобы задать значение параметра по умолчанию, в списке параметров функции достаточно после имени переменной написать знак равенства и нужное значение. Параметры со значением по умолчанию идут последними.
Изменяемые типы данных в качестве значений по умолчанию
Рассмотрим определение функции append(), где в качестве значения по умолчанию используется изменяемый тип данных:
Если вызвать функцию так, то мы получим неожиданный результат:
1
2
3
print(append(10))print(append(5))print(append(1))
1
2
3
4
# Вывод:
[10]
[10, 5]
[10, 5, 1]
Значение по умолчанию для параметра создается единожды при определении функции (обычно при загрузке модуля) и становится её атрибутом (свойством). Поэтому, если значение по умолчанию изменяемый объект, то его изменение повлияет на каждый следующий вызов функции. Для решения проблемы можно использовать константу None в качестве значения параметра по умолчанию, а в теле функции устанавливать нужное значение:
В заголовке функции my_func() указан всего один параметр args, но со звездочкой перед ним. Звездочка в определении функции означает, что переменная (параметр) args получит в виде кортежа все аргументы, переданные в функцию при ее вызове от текущей позиции и до конца.
При описании функции можно использовать только один параметр помеченный звездочкой, причем располагаться он должен в конце списка параметров, иначе последующим параметрам не достанется значений.
Параметр со звёздочкой работает, даже если не передать аргументов.
Если мы хотим просуммировать несколько разных значений, не упаковывая их в список, можем написать следующую функцию (списки и кортежи при вызове нужно распаковывать):
Именованные аргументы получаются в виде словаря, что позволяет сохранить имена аргументов в ключах.
Именованные аргументы можно передавать в функцию “пачкой” в виде словаря. Для этого нужно перед словарём поставить две звёздочки.
Параметр **kwargs пишется в самом конце, после последнего аргумента со значением по умолчанию. При этом функция может содержать и *args и **kwargs параметры:
В Python 3 добавили возможность пометить именованные аргументы функции так, чтобы вызвать функцию можно было, только передав эти аргументы по именам. Такие аргументы называются keyword-only и их нельзя передать в функцию в виде позиционных:
Здесь * выступает разделителем: отделяет обычные аргументы (их можно указывать по имени и позиционно) от строго именованных. То есть аргументы x, y и radius могут быть переданы в качестве как позиционных, так и именованных аргументов. При этом аргументы line_width и fill могут быть переданы только как именованные аргументы. Такой разделитель можно использовать только один раз в определении функции. Его нельзя применять в функциях с неограниченным количеством позиционных аргументов *args.
Тогда как функции, объявленные программистом, имеют тип <class 'function'>.
Поскольку функции тоже объекты, работать с ними можно как с остальными объектами: записывать их в переменные, передавать в качестве аргументов другим функциям, возвращать из функций и т.д.
1
2
3
4
5
6
7
8
defhello():print('Hello from function')func=hello# присваиваем переменной func функцию hellofunc()# вызываем функцию# Вывод: Hello from function
Функции, способные в качестве аргумента принимать или/и возвращать другие функции, называются функциями высшего порядка. Функция, определяющая условия сравнения элементов, называется компаратор.
Такие встроенные функции, как min(), max(), sorted() могут принимать необязательный аргумент key – функцию, определяющую, по какому правилу будут сравниваться элементы (значение key должно быть функцией, принимающей один аргумент и возвращающей на его основе ключ для сравнения).
# Вывод:
-210 # максимальный по модулю элемент
-7 # минимальный по модулю элемент
[-7, 8, 10, 32, -50, 87, -100, 117, -210]
1
2
3
4
5
6
7
8
9
10
11
12
defcompare_by_second(point):returnpoint[1]defcompare_by_sum(point):returnpoint[0]+point[1]points=[(1,-1),(2,3),(-10,15),(10,9),(7,18),(1,5),(2,-4)]print(sorted(points,key=compare_by_second))# сортируем по второму значению кортежаprint(sorted(points,key=compare_by_sum))# сортируем по сумме кортежа
Функции в качестве возвращаемых значений других функций
В Python можно определять функцию внутри функции, ведь функция это объект:
1
2
3
4
5
6
7
8
9
defgenerator():defhello():print('Hello from function!')returnhellofunc=generator()func()# Вывод: Hello from function!
Мы можем написать генератор функций, который по параметрам a,b,c, построит и вернет нам конкретный квадратный трехчлен:
Вложенную функцию (square_polynom()), которая использует параметры внешней функции (generator_square_polynom()), называют замыканием.
Пользовательские атрибуты функций
У объектов функций есть дополнительный атрибут __dict__, являющийся словарем и использующийся для динамического наделения функций дополнительным функционалом. Устанавливать и получать значения из данного атрибута можно, используя два синтаксиса:
Функции, которые принимают и/или возвращают другие функции, называются функциями высшего порядка.
Функция map()
Функция, преобразующая каждый элемент переданного итерируемого объекта (можно воспринимать как классическое представление функции в математике – отображение множества в другое множество). Возможная реализация:
defsquare(x):returnx**2defcube(x):returnx**3numbers=[1,2,-3,4,-5,6,-9,0]strings=map(str,numbers)# используем в качестве преобразователя функцию strabs_numbers=map(abs,numbers)# используем в качестве преобразователя функцию abssquares=map(square,numbers)# используем в качестве преобразователя функцию squarecubes=map(cube,numbers)# используем в качестве преобразователя функцию cubeprint(strings)print(abs_numbers)print(squares)print(cubes)
Мы также можем строить цепочки преобразований, несколько раз вызывая функцию map() (сначала мы преобразуем список строк в список чисел, затем находим их модуль внешней функцией map()):
Эта функция отображает часть элементов итерируемого объекта по определённому критерию. Возможная реализация:
1
2
3
4
5
6
7
deffilter(function,items):result=[]foriteminitems:iffunction(item):result.append(item)# добавляем элемент item если функция function вернула значение Truereturnresult
Функция filter() применяет предикат function к каждому элементу и добавляет в итоговый список только те элементы, для которых предикат вернул True.
Функция, применяющая другую функцию к итерируемому объекту. Имеет сигнатуру map(func, *iterables). В отличии от нашей реализации она может принимать сразу несколько последовательностей, переменное количество аргументов. Под подпоследовательностями имеются ввиду списки, строки, кортежи, множества, словари.
1
2
3
4
5
6
7
8
9
10
defincrease(num):returnnum+7numbers=[1,2,3,4,5,6]new_numbers=map(increase,numbers)# используем встроенную функцию map()print(new_numbers)# Вывод: <map object at 0x...>
Вернулся итерируемый объект <map object at 0x...>. Подобные ему объекты называются итераторами. Если мы хотим получить список/кортеж из итератора, нужно воспользоваться функцией list()/tuple(), а если распаковать, то * (при этом сделать эти действия возможно только единожды, т.к. итератор “исчерпывает” себя).
Функции map() можно передать несколько последовательностей. В этом случае в функцию обратного вызова func будут передаваться сразу несколько элементов, расположенных в последовательностях на одинаковых позициях. При этом, если в последовательностях разное количество элементов, то последовательность с минимальным количеством элементов становится ограничителем.
Пример удобного использования функции map(), которой передано две последовательности:
1
2
3
4
5
6
7
8
circle_areas=[3.56773,5.57668,4.31914,6.20241,91.01344,32.01213]result1=list(map(round,circle_areas,[1]*6))# округляем числа до 1 знака после запятойresult2=list(map(round,circle_areas,range(1,7)))# округляем числа до 1,2,...,6 знаков после запятойprint(circle_areas)print(result1)print(result2)
Функция отображает часть элементов итерируемого объекта по определённому критерию. Имеет сигнатуру filter(func, iterable). В отличии от нашей реализации она может принимать любой итерируемый объект (список, строку, кортеж, и т.д.).
1
2
3
4
5
6
7
8
9
10
deffunc(elem):returnelem>=0numbers=[-1,2,-3,4,0,-20,10]positive_numbers=list(filter(func,numbers))# преобразуем итератор в списокprint(positive_numbers)# Вывод: [2, 4, 0, 10]
Функция filter() также возвращает итератор.
Встроенной функции filter() можно в качестве первого параметра func передать значение None. В таком случае каждый элемент последовательности будет проверен на соответствие значению True. Если элемент в логическом контексте возвращает значение False, то он не будет добавлен в возвращаемый результат. В следующем коде значения списка [0, '', None, [], ()] позиционируется как False:
Функция, применяющая указанную функцию к элементам последовательности, сводя её к единственному значению. Имеет сигнатуру reduce(func, iterable, initializer=None). Если начальное значение не установлено, то в его качестве используется первое значение из последовательности iterable.
1
2
3
4
5
6
7
8
9
10
11
12
fromfunctoolsimportreducedeffunc(a,b):returna+bnumbers=[1,2,3,4,5,6,7,8,9,10]total=reduce(func,numbers,0)# в качестве начального значения 0print(total)# Вывод: 55
Анонимные функции
lambda – безымянные однострочные функции (называются анонимными или лямбда-функциями). По сути эти функции являются выражениями, при этом они имеют такой же тип данных, как обычные функции – <class 'function'>. После определения их можно сразу вызвать: print((lambda х, у: х + у)(5, 10)) # 5 + 10.
Общий формат определения: lambda список_параметров: выражение. В теле лямбда-функции нельзя использовать несколько действий и циклы, но можно использовать тернарный условный оператор.
Применение таких функций оправдано в следующих случаях:
однократное использование функции;
передача функций в качестве аргумента другим функциям;
возвращение функции в качестве результата другой функции.
f1=lambda:10+20# функция без параметровf2=lambdaх,у:х+у# функция с двумя параметрамиf3=lambdaх,у,z:х+у+z# функция с тремя параметрамиprint(f1())print(f2(5,10))print(f3(5,10,30))
Лямбда-функции для нетипичной сортировки кортежей:
1
2
3
4
points=[(1,-1),(2,3),(-10,15),(10,9),(7,18),(1,5),(2,-4)]print(sorted(points,key=lambdapoint:point[1]))# сортируем по второму значению кортежаprint(sorted(points,key=lambdapoint:point[0]+point[1]))# сортируем по сумме элементов кортежа
Передача лямбда-функций в качестве аргументов
Функция map():
1
2
3
4
5
6
7
8
9
10
11
numbers=[1,2,3,4,5,6]new_numbers1=list(map(lambdax:x+1,numbers))# увеличиваем на 1new_numbers2=list(map(lambdax:x*2,numbers))# удваиваемnew_numbers3=list(map(lambdax:x**2,numbers))# возводим в квадратstrings=['a','b','c','d','e']numbers=[3,2,1,4,5]new_strings=list(map(lambdax,y:x*y,strings,numbers))
Функция filter():
1
2
3
4
5
6
7
8
9
10
11
numbers=[-1,2,-3,4,0,-20,10,30,-40,50,100,90]positive_numbers=list(filter(lambdax:x>0,numbers))# положительные числаlarge_numbers=list(filter(lambdax:x>50,numbers))# числа, большие 50even_numbers=list(filter(lambdax:x%2==0,numbers))# четные числаwords=['python','stepik','beegeek','iq-option']new_words1=list(filter(lambdaw:len(w)>6,words))# слова длиною больше 6 символовnew_words2=list(filter(lambdaw:'e'inw,words))# слова содержащие букву e
Возвращение лямбда-функции в качестве результата другой функции
Следующий пример показывает, что анонимные функции являются замыканиями, т.е. возвращаемая функция запоминает значения переменных a, b, c из внешнего окружения:
Встроенная функция all() возвращает значение True, если все элементы переданной ей коллекции истинны, и False в противном случае. При работе со словарями функция all() проверяет на соответствие параметрам Trueключи словаря.
Встроенная функция any() возвращает значение True, если хотя бы один элемент переданной ей коллекции является истинным, и False в противном случае. При работе со словарями функция any() проверяет на соответствие True ключи словаря.
Следующий код проверяет, все ли элементы списка больше 10:
1
2
3
4
5
6
7
8
numbers=[17,90,78,56,231,45,5,89,91,11,19]result=all(map(lambdax:Trueifx>10elseFalse,numbers))# анонимную функцию можно упростить до lambda x: x > 10ifresult:print('Все числа больше 10')else:print('Хотя бы одно число меньше или равно 10')
Следующий код проверяет, чётен ли хотя бы один элемент коллекции:
1
2
3
4
5
6
7
8
numbers=[17,91,78,55,231,45,5,89,99,11,19]result=any(map(lambdax:x%2==0,numbers))ifresult:print('Хотя бы одно число четное')else:print('Все числа нечетные')
Функция enumerate()
Встроенная функция enumerate() возвращает кортеж из индекса элемента и самого элемента переданной ей коллекции: enumerate(iterable, start), где iterable – итерируемый объект (коллекция), а start – необязательный параметр, задающий начальное значение индекса (по умолчанию start = 0). Эта функция возвращает объект-итератор, который можно перебрать, преобразовать в список функцией list() или распаковать *.
Встроенная функция zip() объединяет отдельные элементы из каждой переданной ей коллекции в кортежи. Также возвращает итератор, который можно перебрать, преобразовать или распаковать. Если функции zip() передать итерируемые объекты, имеющие разную длину, то объект с наименьшим количеством элементов определяет итоговую длину.