Skip to content

janusnic/py-21v

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

py - 21v

Функции в Python

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

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

Именные функции, инструкция def

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

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

  1. Пример функции в Python:
def hello():
    print('hello')

def my_function(argument):
    print argument

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

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

Например:

my_function("abracadabra")

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

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

def bigger(a,b):
    if a > b:
        return a # Если a больше чем b, то возвращаем b и прекращаем выполнение функции
    return b # Незачем использовать else. Если мы дошли до этой строки, то b, точно не меньше чем a
 
# присваиваем результат функции bigger переменной num
num = bigger(23,42)
  1. Определим простейшую функцию:
def add(x, y):
    return x + y

Инструкция return говорит, что нужно вернуть значение В нашем случае функция возвращает сумму x и y.

Теперь мы ее можем вызвать:

add(1, 10)
add('abc', 'def')

Например:

def hello():
    print "Hello"

def area(w, h):
    return w * h

def print_welcome(name):
    print "Welcome", name

hello()
hello()

print_welcome("Fred")
w = 4
h = 5
print "width =", w, "height =", h, "area =", area(w, h)

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

def func():
    pass

print(func())

absolute_value

a = 23
b = -23

if a < 0:
    a = -a
if b < 0:
    b = -b                         #Or use the command: elif (if+else)
if b > 0:
  elif:
    print("ok")
    print("Nope")

def absolute_value(n):

def absolute_value(n):
    if n < 0:
        n = -n
    return n

a = 23
b = -23

if absolute_value(a) == absolute_value(b):
    print "The absolute values of", a, "and", b, "are equal"
else:
    print "The absolute values of", a, "and", b, "are different"

задача нахождения наибольшего из двух чисел.

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

def max(a, b):
    if a > b:
        return a
    else:
        return b

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

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

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

# 1.py
def a(a,b):
    print a,b

a(5,6)

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

  • Обязательные аргументы (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 a(b=4,c=5):
     print b,c
  
 a()
 a(12,13)
 a(b=15,c=16)
 
 

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

 def a(b=[1]):
     b[0] += 1
     b.append(1)
     print b
  
a()
a()
a()

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

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

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

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

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

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

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

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

Необязательные и именованные аргументы

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

  1. help — функция с двумя необязательными аргументами

def help(object, spacing=10, collapse=1):

Аргументы spacing и collapse могут быть опущены при вызове, так как для них определены значения по умолчанию. Аргумент object не имеет значения по умолчанию, поэтому должен быть указан всегда. Если функция help вызывается только с одним аргументом, то spacing принимает значение 10 и collapse принимает значение 1. Если help вызывается с двумя аргументами, collapse также принимает значение 1.

Python позволяет передавать аргументы в произвольном порядке по имени.

Возможные способы вызова help

help(odbchelper)  # С одним аргументом, spacing и collapse получают значения по умолчанию, 10 и 1 соответственно.
help(odbchelper, 12) # С двумя аргументами, collapse получает значение по умолчанию 1.
help(odbchelper, collapse=0)  # Здесь вы явно указываете имя аргумента, collapse, для которого передается значение. Аргумент spacing по-прежнему получает значение по умолчанию 10.
help(spacing=15, object=odbchelper) # Даже обязательные аргументы (в данном случае — object), которые не имеют значения по умолчанию, могут быть переданы по имени, и именованные аргументы могут быть указаны в произвольном порядке.

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

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

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

def func(a, b, c=2): # c - необязательный аргумент
    return a + b + c

func(1, 2)  # a = 1, b = 2, c = 2 (по умолчанию)

func(1, 2, 3)  # a = 1, b = 2, c = 3

func(a=1, b=3)  # a = 1, b = 3, c = 2

func(a=3, c=6)  # a = 3, c = 6, b не определен

calc

def add(a, b):
    print "ADDING %d + %d" % (a, b)
    return a + b

def subtract(a, b):
    print "SUBTRACTING %d - %d" % (a, b)
    return a - b

def multiply(a, b):
    print "MULTIPLYING %d * %d" % (a, b)
    return a * b

def divide(a, b):
    print "DIVIDING %d / %d" % (a, b)
    return a / b


print "Let's do some math with just functions!"

age = add(30, 5)
height = subtract(78, 4)
weight = multiply(90, 2)
iq = divide(100, 2)

print "Age: %d, Height: %d, Weight: %d, IQ: %d" % (age, height, weight, iq)


# A puzzle for the extra credit, type it in anyway.
print "Here is a puzzle."

what = add(age, subtract(height, multiply(weight, divide(iq, 2))))

print "That becomes: ", what, "Can you do it by hand?"

  1. Произвольное количество аргументов

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

Например:

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

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

# 8.py
def func(*args):
    return args

func(1, 2, 3, 'abc')

func()
()
func(1)
(1,)

Как видно из примера, args - это кортеж из всех переданных аргументов функции, и с переменной можно работать также, как и с кортежем.

Обозначается звездочкой перед аргументом - *args

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

Пример. Определение функции с переменным количеством аргументов:

# 9.py
def a(*args):
    print type(args)
    print args
 
a(1,2,3,4,5)

Пример 10. Передача списка в функцию, как набора аргументов:

def a(*args):
    print args

a(1,2,3) # Переменное к-во аргументов
a([1,2,3]) # Список (передается как один аргумент)
a(*[1,2,3]) # Список со звездочкой (передается как переменное к-во аргументов)

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

Обозначается двумя звездочками перед аргументом - **kwargs Внутри функции выглядит как словарь, с ключами, соответствующими именам аргументов, указанными при вызове функции. Передать словарь при вызове функции как набор именованных аргументов можно, приписав две звездочки перед обозначением словаря. Напримиер так: **kwargs

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

def a(**kwargs):
    print kwargs

a()
a(b=1,c=2)

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

 def a(**kwargs):
     print kwargs
  
 d = {'k1':1,'k2':2} 
 
 a(k1=d) # Словарь передан как один именованный аргумент.
 a(**d) # Словарь передан как произвольное количество именованных аргументов.

Все виды параметров вместе

def a(b,c,*args,**kwargs):
    print b,c,args,kwargs
 
a(1,2)
a(1,2,3,4)
a(1,2,5,6,d=8,e=9,f=10)

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

def func(**kwargs):
   return kwargs

func(a=1, b=2, c=3)
{'a': 1, 'c': 3, 'b': 2}
func()
{}
func(a='python')
{'a': 'python'}

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

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

Если при вызове функции подставим в качестве значения аргумента переменную, а в теле функции мы меняем значение аргумента, то то, что произойдет, зависит от того, с каким значение связана наша переменная. Если переменная связана с неизменяемым значением, например int, str, tulpe, то естественно, это значение не изменится. А вот если переменная связана со списком, словарем или классом, то значение связанного с переменной объекта изменится.

Не изменяется 14:

 def a(b):
     b = 2
 
 c = 3
 print c
 a(c)
 print c
  

Изменяется 15:

 def a(b):
     b[0] = 2
  
 c = [3]
 print c
 a(c)
 print c
  1. если нам нужно "передать параметр по ссылке", как в Си, делать этого не следует, может получиться не то, что хотим. Цель передачи параметра по ссылке в Си - вернуть несколько значений из функции, путем изменения значений по ссылкам внутри функции. В питоне можно возвращать кортеж, поэтому, если нужно вернуть нескоько значений, нужно возвращать кортеж и присваивать его значения переменным.

  2. во избежание "боковых эффектов", значениями по умолчанию лучше делать неизменяемые типы (None, int, str, tulpe)

def a():
    return(5,6)
 
b = 1
c = 2
 
print b,c
b,c = a()
print b,c

Передаваемые параметры

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

name = input('Имя...')
def print_name(name):  #В скобках - параметр, который получает функция
    print('Твое имя - ' + name)
a=input('Да?')
if a == 'да':
    print_name(name)  
elif a== 'нет':
    print_name('нет ') #Передаем "нет " как параметр 
#Еще какой-нибудь код, где мы вызываем эту функцию

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

name = input('Имя...')
def print_name(name='none'):  #В скобках - параметр, который получает функция
    print('Твое имя - ' + name)

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

def print_name(name='none'):  
    print('Твое имя - ' + name)

#Значение по-умолчанию
print_name()

#Способ 1, свое значение
print_name('царь')

#Способ 2, свое значение
print_name(name='котик')

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

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

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

  • Глобальные переменные
  • Локальные переменные
# 1.py

a = 4
 
def print_func():
    a = 17
    print "in  print_func a = ", a

print_func()
print "a = ", a,"which is global variable assigned prior to the function print_func"

Если записать в IDLE приведенную ниже функцию, и затем попробовать вывести значения переменных, то обнаружится, что некоторые из них почему-то не существуют:

# 2.py
def mathem(a,b):
    a = a/2
    b = b+10
    print(a+b)
 
num1 = 100
num2 = 12

mathem(num1,num2)

print num1

print num2

print a
print b

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

А вот переменных a и b оказывается нет и в помине (ошибка "name 'b' is not defined" переводится как "переменная b не определена"). Эти переменные существуют лишь в момент выполнения функции и называются локальными. В противовес им, переменные num1 и num2 видны не только во внешней ветке, но и внутри функции:

def mathem2():
   print(num1+num2)
 
mathem2()

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

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


# 3.py глобальная переменная age
age = 44
 
def info():
    print age # Печатаем глобальную переменную age
 
def local_info():
    age = 22 # создаем локальную переменную age 
    print age
 
info() # напечатает 44
local_info() # напечатает 22

слово global

Глобальные переменные доступны отовсюду:

def simple():
    global b
    b='Дафтер'

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

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

Например:

# 4.py глобальная переменная age
age = 13
 
# функция изменяющая глобальную переменную
def get_older():
    global age
    age += 1
 
print age # напечатает 13
get_older() # увеличиваем age на 1
print age # напечатает 14

foo() 1-4 исключение UnboundLocalError

Этот код:

x = 10
def bar():
   print(x)
bar()

работает, но следующий код:

x = 10
def foo():
    print(x)
    x += 1

приводит к UnboundLocalError:

foo()
Traceback (most recent call last):
  ...
UnboundLocalError: local variable 'x' referenced before assignment

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

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

В примере выше можно получить доступ к переменной, объявив её глобальной:

x = 10
def foobar():
    global x
    print(x)
    x += 1
foobar()
10

Это явное объявление требуется для того, чтобы напомнить вам, что (в отличие от внешне аналогичной ситуации с переменными класса и экземпляра), вы на самом деле, изменяете значение переменной во внешней области видимости:

print(x)
11

nonlocal - python3

Вы можете сделать подобную вещь во вложенной области видимости использованием ключевого слова nonlocal:

def foo():
   x = 10
   def bar():
       nonlocal x
       print(x)
       x += 1
   bar()
   print(x)
foo()
10
11

5.py Complex example

a_var = 10
b_var = 15
c_var = 25

def a_func(a_var):
    print "in a_func a_var = ", a_var
    b_var = 100 + a_var
    d_var = 2 * a_var
    print "in a_func b_var = ", b_var
    print "in a_func d_var = ", d_var
    print "in a_func c_var = ", c_var
    return b_var + 10

c_var = a_func(b_var)

print "a_var = ", a_var
print "b_var = ", b_var
print "c_var = ", c_var
print "d_var = ", d_var
The output is:
 in a_func a_var =  15
 in a_func b_var =  115
 in a_func d_var =  30
 in a_func c_var =  25
 a_var =  10
 b_var =  15
 c_var =  125
 d_var = 
 
 Traceback (most recent call last):
  File "C:\Python24\def2", line 19, in -toplevel-
     print "d_var = ", d_var
 
 NameError: name 'd_var' is not defined

Рекурсия

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

def short_story():
    print("У попа была собака, он ее любил.")
    print("Она съела кусок мяса, он ее убил,")
    print("В землю закопал и надпись написал:")
    short_story()

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

факториалом числа, например, 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)

Хорошо известно, что 0!=1, 1!=1. А как вычислить величину n! для большого n? Если бы мы могли вычислить величину (n-1)!, то тогда мы легко вычислим n!, поскольку n!=n⋅(n-1)!. Но как вычислить (n-1)!? Если бы мы вычислили (n-2)!, то мы сможем вычисли и (n-1)!=(n-1)⋅(n-2)!. А как вычислить (n-2)!? Если бы... В конце концов, мы дойдем до величины 0!, которая равна 1. Таким образом, для вычисления факториала мы можем использовать значение факториала для меньшего числа. Это можно сделать и в программе на Питоне:

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

print(factorial(5))

ВЫЧИСЛЕНИЕ СУММЫ НАТУРАЛЬНЫХ ЧИСЕЛ ОТ 1 ДО N

Если n==1, то сумма равна 1. Иначе сумма чисел от 1 до n равна сумме чисел от 1 до n−1, которую можно вычислить при помощи рекурсии плюс число n.

def sum(n):
    if n == 1:
        return 1
    else:
        return n + sum(n — 1)

ПРОВЕРКА СТРОКИ НА ПАЛИНДРОМНОСТЬ

Строка является палиндромом, если она одинаково читается как справа налево, так и слева направо. Напишем функцию IsPalindrome, которая возвращает значение типа bool в зависимости от того, является ли строка палиндромом. Крайнее значение — пустая строка или строка из одного символа всегда палиндром. Рекурсивный переход — строка является палиндромом, если у нее совпадают первый и последний символ, а также строка, полученная удалением первого и последнего символа является палиндромом.

def IsPalindrome(S):
    if len(S) <= 1:
        return True
    else:
        return S[0] == S[-1] and IsPalindrome(S[1:-1])

СУММИРОВАНИЕ СПИСКА

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

def Sum(A):
    if len(A) == 0:
        return 0
    else:
        return Sum(A[:-1]) + A[-1]

НАИБОЛЬШЕЕ ЗНАЧЕНИЕ В СПИСКЕ

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

def Max(A):
    if len(A) == 1:
        return A[0]
    else:
        return max(Max(A[:-1]), A[-1])

ЧИСЛА ФИБОНАЧЧИ

Последовательность Фибоначчи задана так: F0=0, F1=1, при n>1 число Фибоначчи с номером n вычисляется как Fn=Fn−1+Fn−2. Для рекурсивного вычисления чисел Фибоначчи достаточно аккуратно запрограммировать эти соотношения:

def Fib(n):
    if n <= 1:
        return n
    else:
        return Fib(n — 1) + Fib(n — 2)

БЫСТРОЕ ВОЗВЕДЕНИЕ В СТЕПЕНЬ

Одним из полезных применений рекурсии является алгоритм быстрого возведения в степень. Если вычислять степень числа an при помощи простого цикла, то понадобится n−1 умножение. Но можно использовать рекуррентные соотношения:

an=an−1×a, при нечетном n
an=(an/2)2, при четном n.

Это позволяет записать алгоритм, который будет выполнять не более, чем 2∗log2n умножений:

def power(a, n):
    if n == 0:
        return 1
    elif n % 2 == 1:
        return power(a, n - 1) * a
    else:
        return power(a, n // 2) ** 2

ХАНОЙСКИЕ БАШНИ

Другой классической задачей, решаемой при помощи рекурсии, является задача о Ханойских башнях. Головоломка “Ханойские башни” состоит из трех стержней, пронумерованных числами 1, 2, 3. На стержень 1 надета пирамидка из n дисков различного диаметра в порядке возрастания диаметра. Диски можно перекладывать с одного стержня на другой строго по одному, при этом диск нельзя класть на диск меньшего диаметра. Необходимо переложить всю пирамидку со стержня 1 на стержень 3 за минимальное число перекладываний. Необходимо написать программу, которая для данного числа дисков n печатает последовательность перекладываний, необходимую для решения головоломки. Сначала нужно подумать, как переложить пирамидку из n дисков с одного стержня на другой. Для этого нужно прежде всего перенести самый большой диск. Но чтобы перенести этот диск нужно всю пирамидку без этого диска, то есть пирамидку из n−1 диска перенести на третий стержень, затем перенести один самый большой диск, затем перенести пирамидку из n−1 диска на тот стержень, на который переместили самый большой диск. Напишем рекурсивную функцию move(n, start, finish), которая печатает последовательность перекладываний, необходимых для перемещения пирамидки из n дисков со стержня номер start на стержень номер finish. Простой случай — n==1, в этом случае рекурсия не нужна и нужно просто переместить один диск.

def move(n, start, finish):
    if n == 1:
        print("Перенести диск 1 со стержня", start, "на стержень", finish)
    else:
        temp = 6 — start — finish # Вспомогательный колышек
        move(n — 1, start, temp)
        print("Перенести диск", n, "со стержня", start, "на стержень", finish)
        move(n — 1, temp, finish)
# Для решения головоломки из 10 дисков вызываем так:
move(10, 1, 3)

Решение можно сделать проще, если понять, что крайний случай — это случай n==0, в этом случае для перемещения пирамидки из 0 дисков… просто ничего не нужно делать!

def move(n, start, finish):
    if n > 0:
        temp = 6 — start — finish # Вспомогательный колышек
        move(n — 1, start, temp)
        print("Перенести диск", n, "со стержня", start, "на стержень", finish)
        move(n — 1, temp, finish)

ОГРАНИЧЕНИЕ НА ГЛУБИНУ РЕКУРСИИ

По умолчанию глубина рекурсии в языке Питон ограничена 1000 вызовов. Это ограничение можно поднять при помощи функции setrecursionlimit из модуля system. Например, чтобы увеличить возможную глубину рекурсии до 10000 нужно в начале программы выполнить две инструкции:

import sys
sys.setrecursionlimit(10000)

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

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

Две наиболее распространенные причины для бесконечной рекурсии:

  • Неправильное оформление выхода из рекурсии. Например, если мы в программе вычисления факториала забудем поставить проверку if n == 0, то factorial(0) вызовет factorial(-1), тот вызовет factorial(-2) и т. д.
  • Рекурсивный вызов с неправильными параметрами. Например, если функция factorial(n) будет вызывать factorial(n), то также получится бесконечная цепочка.

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

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

Анонимные функции, инструкция lambda

Помимо def есть lambda, c их помощью можно создавать объекты функций.

Выражение lambda

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

lambda - анонимны, то есть без имени.

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

lambda argument1, argument2,... argumentN : выражение, использующее аргументы

Различия lambda от def:

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

  • Тело lambda – это не блок инструкций, а единственное выражение. Тело lambda-выражения сродни тому, что вы помещаете в инструкцию return внутри определения def, – вы просто вводите результат в виде выражения вместо его явного возврата.

Без выражения lambda:

>>> def func(x, y, z): return x + y + z
...
>>> func(2, 3, 4)
9

С выражением lambda:

>>> f = lambda x, y, z: x + y + z
>>> f(2, 3, 4)
9

Использование значений по умолчанию в lambda-выражениях:

>>> x = (lambda a=”fee”, b=”fie”, c=”foe”: a + b + c)
>>> x(“wee”)
‘weefiefoe’

Те же самые правила поиска переменных в областях видимости, что и для вложенных инструкций def:

  • lambda-выражения создают локальную область видимости, как и вложенные инструкции def, и ав томатически получают доступ к именам в объемлющих функциях, в модуле и во встроенной области видимости (в соответствии с правилом LEGB).
>>> def knights():
...     title = ‘Sir’
...     action = (lambda x: title + ‘ ‘ + x) # Заголовок в объемлющей def
...     return action                        # Возвращает функцию
...
>>> act = knights()
>>> act(‘robin’)
‘Sir robin’

Когда можно использовать lambda-выражения:

  • Для создания таблиц переходов, которые представляют собой списки или словари действий, выполняемых по требованию. Например:
L = [lambda x: x**2,   # Встроенные определения функций
     lambda x: x**3, 
     lambda x: x**4]   # Список из трех функций

for f in L:
    print(f(2))        # Выведет 4, 8, 16

print(L[0](3))         # Выведет 9

Тот же пример без использования lambda:

def f1(x): return x ** 2
def f2(x): return x ** 3   # Определения именованных функций
def f3(x): return x ** 4

L = [f1, f2, f3]           # Ссылка по имени

for f in L:
    print(f(2))            # Выведет 4, 8, 16

print(L[0](3))             # Выведет 9

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

>>> key = ‘got’
>>> {‘already’: (lambda: 2 + 2),
...  ‘got’:     (lambda: 2 * 4),
...  ‘one’:     (lambda: 2 ** 6)}[key]()
8

Тот же пример без использования lambda:

>>> def f1(): return 2 + 2
...
>>> def f2(): return 2 * 4
...
>>> def f3(): return 2 ** 6
...
>>> key = ‘one’
>>> {‘already’: f1, ‘got’: f2, ‘one’: f3}[key]()
64

Так же возможна реализация логики выбора внутри lambda-функций:

>>> lower = (lambda x, y: x if x < y else y)
>>> lower(‘bb’, ‘aa’)
‘aa’
>>> lower(‘aa’, ‘bb’)
‘aa’

Вложенные lambda-выражения и области видимости:

Соблюдается правило LEGB. Например, lambda-выражение находится внутри инструкции def – типичный случай – и потому получает значение имени x из области видимости объемлющей функции, имевшееся на момент ее вызова:

>>> def action(x):
...     return (lambda y: x + y) # Создать и вернуть ф-цию, 
...                              # запомнить x
>>> act = action(99)
>>> act
<function <lambda> at 0x00A16A88>
>>> act(2)         # Вызвать функцию, созданную ф-цией action
101

Предыдущая инструкция def в виде lambda-выражения:

>>> action = (lambda x: (lambda y: x + y))
>>> act = action(99)
>>> act(3)
102
>>> ((lambda x: (lambda y: x + y))(99))(4)
103

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

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

func = lambda x, y: x + y
func(1, 2)
3
func('a', 'b')
'ab'
(lambda x, y: x + y)(1, 2)
3
(lambda x, y: x + y)('a', 'b')
'ab'

lambda функции, в отличие от обычной, не требуется инструкция return, а в остальном, ведет себя точно так же:

func = lambda *args: args
func(1, 2, 3, 4)
(1, 2, 3, 4)

sorted()

sorted([[3, 4], [3, 5], [1, 2], [7, 3]], key=lambda x: x[1])
[[1, 2], [7, 3], [3, 4], [3, 5]]
  1. Почему анонимные функции (lambda), определенные в цикле с разными значениями, возвращают один и тот же результат? Например, вы написали следующий код:
squares = []
for x in range(5):
   squares.append(lambda: x**2)

Это даёт вам список из 5 функций, считающих x**2. Можно ожидать, что, будучи вызванными, они вернут, соответственно, 0, 1, 4, 9, и 16. Однако, вы увидите, что все они возвращают 16:

squares[2]()
16
squares[4]()
16

Это случается, поскольку x не является локальной для lambda, а определена во внешней области видимости, и получается тогда, когда она вызывается - а не когда определяется.

В конце цикла, x=4, поэтому все функции возвращают 4**2, то есть 16. Это можно также проверить, изменив значение x и посмотрев на результат:

x = 8
squares[2]()
64

Чтобы избежать подобного, необходимо сохранять значения переменных локально:

squares = []
for x in range(5):
   squares.append(lambda n=x: n**2)

Здесь, n=x создаёт локальную для функции переменную n и вычисляется в момент определения функции:

squares[2]()
4
squares[4]()
16

Это применимо не только к анонимным, а также и к обычным функциям.

closure

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

def newfunc(n):
    def myfunc(x):
        return x + n
    return myfunc

new = newfunc(100)  # new - это функция
new(200)
300

closure example:

def attribution(name):
   return lambda x: x + ' -- ' + name

pp = attribution('John')
pp('Dinner is in the fridge')
'Dinner is in the fridge -- John'

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

В языке Python вы можете документировать функции, снабжая их строками документации.

def buildConnectionString(params):
    """Создает и возвращает строку соединения из словаря параметров."""

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

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

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

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

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

# На данном этапе мы еще не указываем имена переменных
def rectangle_area_finder( ):
    """
    >>> rectangle_area_finder(3, 5)
    15
    >>> rectangle_area_finder(17.2, 6)
    103.2
    """

Указать типы данных, которые принимает функция и тип данных, который она возвращает

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

def rectangle_area_finder( ):
    """
    (num, num) -> num    
 
    >>> rectangle_area_finder(3, 5)
    15
    >>> rectangle_area_finder(17.2, 6)
    103.2
    """

Подобрать подходящие названия для переменных

# Поскольку это математическая функция нам вполне подойдут имена 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
    """

Написать краткое, но содержательное описание функции

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
    """

Написать собственно тело функции

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

Функция готова! Осталось вызвать ее с указанными в примерах аргументами

func/area2.py

# 
print
def hello():
    print 'Hello!'

def area(width, height):
    return width * height

def print_welcome(name):
    print 'Welcome,', name

name = raw_input('Your Name: ')
hello(),
print_welcome(name)
print
print 'To find the area of a rectangle,'
print 'enter the width and height below.'
print
w = input('Width: ')
while w <= 0:
    print 'Must be a positive number'
    w = input('Width: ')

h = input('Height: ')
while h <= 0:
    print 'Must be a positive number'
    h = input('Height: ')

print 'Width =', w, 'Height =', h, 'so Area =', area(w, h)

temperature2.py

# converts temperature to fahrenheit or celsius

def print_options():
    print "Options:"
    print " 'p' print options"
    print " 'c' convert from celsius"
    print " 'f' convert from fahrenheit"
    print " 'q' quit the program"

def celsius_to_fahrenheit(c_temp):
    return 9.0 / 5.0 * c_temp + 32

def fahrenheit_to_celsius(f_temp):
    return (f_temp - 32.0) * 5.0 / 9.0

choice = "p"
while choice != "q":
    if choice == "c":
        temp = input("Celsius temperature: ")
        print "Fahrenheit:", celsius_to_fahrenheit(temp)
    elif choice == "f":
        temp = input("Fahrenheit temperature: ")
        print "Celsius:", fahrenheit_to_celsius(temp)
    elif choice == "p":
        print_options()
    choice = raw_input("option: ")

Sample Run:
Options:
 'p' print options
 'c' convert from celsius
 'f' convert from fahrenheit
 'q' quit the program
option: c
Celsius temperature: 30 
Fahrenheit: 86.0
option: f
Fahrenheit temperature: 60
Celsius: 15.5555555556
option: q

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages