Это простейшая в мире функция. Она не имеет параметров, ничего не делает и ничего не возвращает. Оператор pass
означает "ничего не делай"; он используется там, где синтаксически необходим оператор, а делать ничено не нужно (после if
или elif
, после def
и т.д.).
def f():
pass
f
pass
type(f)
r=f()
print(r)
Эта функция более полезна: она имеет параметр и что-то возвращает.
def f(x):
return x+1
f(1),f(1.0)
f('abc')
Если у функции много параметров, то возникает желание вызывать её попроще в наиболее часто встречающихся случаях. Для этого в операторе def
можно задать значения некоторых параметров по умолчанию (они должны размещаться в конце списка параметров). При вызове необходимо указать все обязательные параметры (у которых нет значений по умолчанию), а необязательные можно и не указывать. Если при вызове указывать параметры в виде имя=значение
, то это можно делать в любом порядке. Это гораздо удобнее, чем вспоминать, является данный параметр восьмым или девятым при вызове какой-нибудь сложной функции.
def f(x,a=0,b='b'):
print(x,' ',a,' ',b)
f(1.0)
f(1.0,1)
f(1.0,b='a')
f(1.0,b='a',a=2)
f(a=2,x=2.0)
Переменные, использующиеся в функции, являются локальными. Присваивание им не меняет значений глобальных переменных с такими же именами.
a=1
def f():
a=2
return a
f()
a
Если в функции нужно использовать какие-нибудь глобальные переменные, их нужно описать как global
.
def f():
global a
a=2
return a
f()
a
Пространство имён устанавливает соответствие между именами переменных и объектами - их значениями. Есть пространство имён локальных переменных функции, пространство имён глобальных переменных программы и пространство имён встроенных функций языка питон. Для реализации пространств имён используются словари.
Если функции передаётся в качестве аргумента какой-нибудь изменяемый объект, и функция его изменяет, то это изменение будет видно снаружи после этого вызова. Мы уже обсуждали эту ситуацию, когда две переменные (в данном случае глобальная переменная и параметр функции) указывают на один и тот же изменяемый объект объект.
def f(x,l):
l.append(x)
return l
l=[1,2,3]
f(0,l)
l
Если в качестве значения какого-нибудь параметра по умолчанию используется изменяемый объект, то это может приводить к неожиданным последствиям. В данном случае исполнение определения функции приводит к созданию двух объектов: собственно функции и объекта-списка, первоначально пустого, который используется для инициализации параметра функции при вызове. Функция изменяет этот объект. При следующем вызове он опять используется для инициализации параметра, но его значение уже изменилось.
def f(x,l=[]):
l.append(x)
return l
f(0)
f(1)
f(2)
Чтобы избежать таких сюрпризов, в качестве значений по умолчанию лучше использовать только неизменяемые объекты.
def f(x,l=None):
if l is None:
l=[]
l.append(x)
return l
f(0)
f(1)
f(2,[0,1])
Эта функция имеет один обязательный параметр плюс произвольное число необязательных. При вызове все такие дополнительные аргументы объединяются в кортеж, который функция может использовать по своему усмотрению.
def f(x,*l):
print(x,' ',l)
f(0)
f(0,1)
f(0,1,2)
f(0,1,2,3)
Звёздочку можно использовать и при вызове функции. Можно заранее построить список (или кортеж) аргументов, а потом вызвать функцию с этими аргументами.
l=[1,2]
f(*l)
c=('a','b')
f(*l,0,*c)
Такую распаковку из списков и кортежей можно использовать не только при вызове функции, но и при построении списка или кортежа.
(*l,0,*c)
[*l,0,*c]
[*l,3]
[3,*l]
Эта функция имеет два обязательных параметра плюс произвольное число необязательных ключевых параметров. При вызове они должны задаваться в виде имя=значение
. Они собираются в словарь, который функция может использовать по своему усмотрению.
def f(x,y,**d):
print(x,' ',y,' ',d)
f(0,1,foo=2,bar=3)
Двойную звёздочку можно использовать и при вызове функции. Можно заранее построить словарь аргументов, сопоставляющий значения именам параметров, а потом вызвать функцию с этими ключевыми аргументами.
d={'foo':2,'bar':3}
f(0,1,**d)
d['x']=0
d['y']=1
f(**d)
Вот любопытный способ построить словарь с ключами-строками.
def f(**d):
return d
f(x=0,y=1,z=2)
Двойную звёздочку можно использовать не только при вызове функции, но и при построении словаря.
d={0:'a',1:'b'}
{**d,2:'c'}
Вот простой способ объединить два словаря.
d1={0:'a',1:'b'}
d2={2:'c',3:'d'}
{**d1,**d2}
Если один и тот же ключ встречается несколько раз, следующее значение затирает предыдущее.
d2={1:'B',2:'C'}
{**d1,3:'D',**d2,3:'d'}
Это наиболее общий вид списка параметров функции. Сначала идут обязательные параметры (в данном случае два), затем произвольное число необязательных (при вызове они будут объединены в кортеж), а затем произвольное число ключевых параметров (при вызове они будут объединены в словарь).
def f(x,y,*l,**d):
print(x,' ',y,' ',l,' ',d)
f(0,1,2,3,foo=4,bar=5)
Функции можно передать функцию в качестве аргумента. Например, эта функция реализует численное интегрирование по формуле Симпсона. Её первый параметр - функция, которую надо проинтегрировать; далее задаются пределы интегрирования и число интервалов, на которое нужно разбить область интегрирования.
def simpson(f,a,b,n):
h=(b-a)/(2*n)
s=0.5*(f(a)+f(b))+2*f(a+h)
x=a+2*h
for i in range(n-1):
s+=f(x)+2*f(x+h)
x+=2*h
return 2/3*h*s
from math import sin,pi
[simpson(sin,0,pi,n) for n in [1,10,100,1000]]
В питоне функции являются гражданами первого сорта. Они могут присутствовать везде, где допустимы объекты других типов - среди элементов списков, значений в словарях и т.д.
def f0(x):
return x+2
def f1(x):
return 2*x
l=[f0,f1]
l
x=2.0
n=1
l[n](x)
Если Вы пишете функцию не для того, чтобы один раз её вызвать и навсегда забыть, то нужна документация, объясняющая, что эта функция делает. Для этого сразу после строчки def
пишется строка. Она называется док-строкой, и сохраняется при трансляции исходного текста на питоне в байт-код (в отличие от комментариев, которые при этом отбрасываются). Обычно эта строка заключается в тройные кавычки и занимает несколько строчек. Док-строка доступна как атрибут __doc__
функции, и используется функцией help
. Вот пример культурно написанной функции, вычисляющей $n$-е число Фибоначчи.
Для проверки типов аргументов, переданных функции, удобно использовать оператор assert
. Если условие в нём истинно, всё в порядке, и он ничего не делает; если же оно ложно, выдаётся сообщение об ошибке.
def fib(n):
"вычисляет n-е число Фибоначчи"
assert type(n) is int and n>0
if n<=2:
return 1
x,y=1,1
for i in range(n-2):
x,y=y,x+y
return y
fib.__doc__
help(fib)
[fib(n) for n in range(1,10)]
fib(-1)
fib(2.0)