Функции позволяют
* расширять язык новыми возможностями без добавления новых синтаксических конструкций (в ранних языках программирования были специальные операторы для ввода и вывода, сейчас это функции)
* избавиться от повторения кода
* упростить длинный код, выделяя его части и заменяя их на короткие понятные идентификаторы
* выделить код, полезный более чем в одной программе (библиотеки, модули)
Функция определяется следующим образом:\
`tt"def" quad "имя" ("параметр"_1, ..., "параметр"_n) tt":" "блок"`
При вызове функции каждому параметру нужно указать значение. Можно либо указать соответствующее количество аргументов (позиционные аргументы):\
`"имя" ("выражение"_1, ..., "выражение"_n)`\
либо указать имя параметра и значение для него (именованные аргументы):\
`"имя" ("параметр"_1="выражение"_1, ..., "параметр"_n="выражение"_n)`
Именованные аргументы могут перечисляться только после позиционных:
```run-python
def sample(a,b,c): print(f"a={a} b={b} c={c}")
sample(1,2,3) # OK
sample(a=1,c=3,b=2) # OK
sample(1,c=3,b=2) # OK
sample(1,2,c=3) # OK
# sample(c=3,1,2) # Ошибка
# sample(1,c=3,2) # Ошибка
```
Параметрам можно задать значения по умолчанию, это значение будет в параметре, если при вызове функции этому параметру не будет явно указано значение. Параметры со значением по умолчанию могут быть указаны только в конце списка параметров функции:
```run-python
def sample(a,b=0,c=1): print(f"a={a} b={b} c={c}")
sample(5,2,3) # OK a=5, b=2, c=3
sample(5,2) # OK a=5, b=2, c=1
sample(5) # OK a=5, b=0, c=1
sample(5,c=3) # OK a=5, b=0, c=3
sample(c=3,a=5) # OK a=5, b=0, c=3
# sample(c=3,b=2) # Ошибка, нет аргумента для a
# def error(a=0,b): pass # Ошибка
```
Есть возможность запретить использовать часть параметров как именованные аргументы, даже если у них есть значение по умолчанию:
```run-python
def sample(a,b=0,/,c=1): print(f"a={a} b={b} c={c}") # a и b - только позиционные, c - позиционный или именованный
sample(5,2,3) # OK a=5, b=2, c=3
sample(5,2) # OK a=5, b=2, c=1
sample(5) # OK a=5, b=0, c=1
# sample(5,b=3) # Ошибка
# sample(c=3,a=5) # Ошибка
```
Так как позиционные аргументы отделены от именованных, можно собрать "лишние" позиционные и именованные аргументы в специальных параметрах со ``*`` и ``**`` соответственно:
```run-python
def sample(a,*b,c=3,**d): print(f"a={a} b={b} c={c} d={d}")
# b - кортеж из лишних позиционных аргументов, d - словарь из лишних именованных аргументов
sample(5) # OK a=5, b=(), c=3, d={}
sample(5,6,7) # OK a=5, b=(6,7), c=3, d={}
sample(5,6,7,x=8,y=9) # OK a=5, b=(6,7), c=3, d={'x':8,'y':9}
sample(5,x=8,y=9,c=10) # OK a=5, b=(), c=10, d={'x':8,'y':9}
s1=[1,3,4]
d1={'c':5,'x':8,'y':9}
sample(*s1,**d1) # подстановка значений из набора s1 как позиционных параметров, а из словаря d1 как именованных
# a=1, b=(3,4), c=5, d={'x':8, 'y':9}
# *d1 интерпретируется как *(d1.keys()), т.е. подстановка набора ключей
```
Для возврата результата из функции используется оператор\
`tt"return" quad "выражение"`\
По умолчанию при завершении блока без ``return`` функция возвращает ``None``; ``return`` без `"выражение"` также возвращает ``None``
Примеры функций:
```run-python
import math
def square(r): # площадь круга
return math.pi*r**2
print(square(2.5))
def solve(a,b,c): # решение квадратного уравнения
d=b**2-4*a*c
if a==0 or d<0:
return None,None # вернуть кортеж
return (-b-math.sqrt(d))/(2*a),(-b+math.sqrt(d))/(2*a)
x1,x2=solve(4,-5,-12)
print(x1,x2)
x1,x2=solve(4,-5,12) # нет решения
print(x1,x2)
def average(*args): # среднее значение ряда чисел
return sum(args)/len(args)
print(average(1,7,10,15))
def integral(f,a,b,n): # найти интеграл функции f на интервале [a,b] как сумму площадей n прямоугольников
h=(b-a)/n
return sum((f((i+0.5)*h+a) for i in range(n)))*h
print(integral(math.sin,0,math.pi,100))
def func(x): return x**2+1
print(integral(func,1,2,100))
```
Функции integral в качестве аргумента передается функция. Если функцию можно определить через единственный оператор ``return``, то в качестве аргумента вместо имени глобальной функции можно указать лямбда-выражение:\
`tt"lambda" quad "параметр"_1, ..., "параметр"_n tt":" "выражение"`
```run-python
def integral(f,a,b,n):
h=(b-a)/n
return sum((f((i+0.5)*h+a) for i in range(n)))*h
print(integral(lambda x:x**2+1,1,2,100))
```
Оператор\
`tt"yield" quad "выражение"`\
позволяет последовательно вернуть несколько значений из функции и превращает функцию в генератор. Оператор ``return`` в такой функции эквивалентен\
``raise StopIteration``
```run-python
def seq1():
yield 4
yield 8
yield 15
yield 16
yield 23
yield 42
for a in seq1():
print(a, end=' ')
print()
def seq2():
for x in [4, 8, 15, 16, 23,42]:
yield x
for a in seq2():
print(a, end=' ')
print()
def seq3():
while True: yield 1 # "бесконечная" последовательность из 1
k=0
for a in seq3():
print(a) # вывести первые 5 значений из последовательности
k+=1
if k>=5: break
```
### Встроенные функции
Функция|Назначение|Пример|Результат
--|--|--|--
*Преобразования и конструкторы объектов*|_|_|_
bool(x)| Преобразование `x` в bool\
(None, нулевые и пустые значения -> False, остальные -> True)|bool('')\
bool(5)|False\
True
chr(x)| преобразование номера `x` в символ|chr(1025)|'Ё'
ord(c)| преобразование символа `c` в номер|ord('Ё')|1025
int(x=0, /, base=10)| преобразование x в целое число,\
для строки можно указать систему счисления|int('12')\
int('12',base=8)\
int(3.7)|12\
14\
3
float(x=0.0)|преобразование x в число с плавающей точкой|float(12)\
float('3.7')|12.0\
3.7
complex(x)\
complex(real=0, imag=0)|преобразование x в комплексное число|complex('1+2j')\
complex(1)\
complex(1,2)|1+2j\
1+0j\
1+2j
bin(x)|преобразование x в строку с бинарным представлением числа|bin(12)|'0b1100'
oct(x)|преобразование x в строку с восьмеричным представлением числа|oct(12)|'0o14'
hex(x)|преобразование x в строку с шестнадцатеричным представлением числа|hex(12)|'0xc'
str(x='')\
str(b,encoding, errors='strict')|преобразование в строку\
для строки из байтов можно указать кодировку и реакцию на ошибки|str(1.2)\
str(b'z\xd0\x81','utf-8')|'1.2'\
'zЁ'
iter(p)\
iter(func,stop)|получение итератора (преобразование в генератор)|iter([1,2,3])\
iter(input,'stop')|
bytes(x=b''), bytearray(x=b'')\
bytes(n),bytearray(n)\
bytes(s,encoding, errors='strict')|преобразование в строку или массив из байтов\
создание строки или массива из n байт\
для строки обязательно указать кодировку|bytearray(b'z\xd0')\
bytes(5)\
bytes('zЁ','utf-8')|bytearray(b'z\xd0')\
b'\x00\x00\x00\x00\x00'\
b'z\xd0\x81'
list()\
list(x)| пустой список\
преобразование x в список|list()\
list('abc')|[]\
['a','b','c']
dict(\*\*kwarg)\
dict(x, \*\*kwarg)| преобразование x и \*\*kwarg в словарь|dict()\
dict([('a',1),('b',2)],c=5)|{}\
{'a': 1, 'b': 2, 'c': 5}
set()\
set(x)\
frozenset(x=set())|пустое множество\
преобразование x в множество|set()\
set('abc')|set()\
{'c', 'a', 'b'}
object()|создание пустого объекта, с которым ничего нельзя делать|object()| <object object at ...>
range(stop)\
range(start, stop, step=1)|создание диапазона|range(5)|range(0, 5)
tuple()\
tuple(x)|создать пустой кортеж\
создать кортеж из последовательности x|tuple()\
tuple([1,2,3])|()\
(1,2,3)
*Работа с объектами и классами*|_|class C:pass\
o=C()
type(obj)|тип объекта|type(o)|<class ``'__main__.C'``>
setattr(obj, name, value)|установка атрибута объекта по имени|setattr(o,'data',5) # или o.data=5|
hasattr(obj, name)|у объекта есть атрибут с указанным именем|hasattr(o,'data')\
hasattr(o,'size')|True\
False
getattr(obj, name)\
getattr(obj, name, default)|получение атрибута объекта по имени|getattr(o,'data') # или o.data\
getattr(o,'size',10)|5\
10
dir(obj)|получение списка имен атрибутов и методов|dir(o)|[..., 'data']
delattr(obj, name)|удаление атрибута|delattr(o,'data') # или del o.data\
o.data| \
Ошибка
isinstance(obj, cls)|объект obj является экземпляром класса cls|isinstance(o, C)|True
issubclass(cls, base)|класс cls яввляется производным от base|issubclass(C, object)|True
super()\
super(cls,obj=None)|объект-заместитель с методами базового класса\
для текущего класса и объекта или cls|super(C)| -
callable(obj) | obj является функцией или есть метод ``__call__``|callable(print)|True
hash(obj)|хэш значения объекта|hash(o)|126946956833
id(obj)|уникальный номер объекта|id(o)|2031151309328
*Работа с последовательностями*|_
len(p)|количество элементов в коллекции или последовательности|len([3, 7])|2
next(it)|следующее значение генератора|g=(x*x for x in range(2,6))\
next(g)|\
4
all(p)| все значения в последовательности истинны | all([2,4])\
all([2,0,4])|True\
False
any(p)| существует истинное значение в последовательности|any([0,4])|True
zip(\*seqs, strict=False)|результатом является генератор, соединяющий\
соответствующие элементы последовательностей или коллекций в кортежи|g=zip([2,7,3],[1,-2,5])\
list(g)|\
[(2, 1), (7, -2), (3, 5)]
reversed(p)|результатом является генератор, возвращающий элементы \
последовательности p в обратном порядке|g=reversed([2,7,3])\
next(g)|\
3
enumerate(p, start=0)|результатом является генератор, возвращающий кортежи\
из номера, начиная со start, и элементов последовательности или коллекции|g=enumerate('abc')\
print(\*g)|\
(0, 'a') (1, 'b') (2, 'c')
max(p, \*, key=None)|максимум из последовательности или коллекции по критерию key|max(['zz','abc','s'])\
max(['zz','abc','s'],key=len)|'zz'\
'abc'
min(p, \*, key=None)|минимум из последовательности или коллекции по критерию key|min(['zz','abc','s'])\
min(['zz','abc','s'],key=len)|'abc'\
's'
sum(p, /, start=0)|сумма элементов последовательности или коллекции +start|sum([2,7,3])|12
sorted(p, /, \*, key=None,\
reverse=False)|упорядоченный список из элементов\
последовательности или коллекции|sorted('SamplE')\
sorted('SamplE',key=str.lower, reverse=True)\
# в обратном порядке, регистр не важен|['E', 'S', 'a', 'l', 'm', 'p']\
['S', 'p', 'm', 'l', 'E', 'a']
filter(func, p)|результатом является генератор, оставляющий значения\
из последовательности или коллекции, для которых\
функция возвращает истину|~~g=filter(lambda x:x>5, [2,7,3])~~\
# g=(x for x in [2,7,3] if x>5)\
next(g)|\
7
map(func,p,\*seqs)|результатом является генератор, применяющий функцию\
ко всем элементам последовательности или коллекции p \
и соответствующим элементам остальных последовательностей|~~g1=map(lambda x:x\*2, [2,7,3])~~\
# g1=(x\*2 for x in [2,7,3])\
print(\*g1)\
~~g2=map(lambda x,y:x+y, [2,7,3],[1,-2,5])~~\
# g2=(x+y for x,y in zip([2,7,3],[1,-2,5]))\
print(\*g2)|\
\
4 14 6\
\
\
3 5 8
*Ввод-вывод*|_
open(file, mode='r', buffering=-1,\
encoding=None, errors=None,\
newline=None, closefd=True,\
opener=None)|возвращает файловый объект для открытого файла|f=open('input.txt','r')\
f.readline()| -
print(\*objects, sep=' ', end='\\n',\
file=None, flush=False)|вывод на печать, можно указать разделитель\
между аргументами и символ в конце печати\
флаг flush принудительно отправляет данные в буфере на вывод,\
необходимо указывать в интерактивных задачах|print(1,2,sep='-')|1-2
input(prompt=None)|ввод строки с подсказкой,\
работает медленно даже при отсутствии prompt, так как выполняет\
flush для вывода и вызывает события аудита|~~input('Введите n:')~~\
from sys import stdin\
stdin.readline()| 'n'\
\
'n\n' (в конце строки оставляет '\n')