Работаем с функциями в python

Функции в Python

Функции в Python определяются 2-мя способами: через определение
или через анонимное описание . Оба этих способа
определения доступны, в той или иной степени, и в некоторых других языках программирования. Особенностью
Python является то, что функция является таким же именованным объектом, как и любой другой объект некоторого
типа данных, скажем, как целочисленная переменная. В листинге 1 представлен простейший пример (файл
func.py из архива python_functional.tgz в разделе «Материалы для скачивания»):

Листинг 1. Определения функций
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys

def show( fun, arg ):
    print( '{} : {}'.format( type( fun ), fun ) )
    print( 'arg={} => fun( arg )={}'.format( arg, fun( arg ) ) )

if len( sys.argv ) > 1: n = float( sys.argv )
else: n = float( input( "число?: " ) )

def pow3( n ):                     # 1-е определение функции
    return n * n * n
show( pow3, n )

pow3 = lambda n: n * n * n         # 2-е определение функции с тем же именем
show( pow3, n )

show( ( lambda n: n * n * n ), n ) # 3-е, использование анонимного описание функции

При вызове всех трёх объектов-функций мы получим один и тот же результат:

$ python func.py 1.3
<type 'function'> : <function pow3 at 0xb7662844>
arg=1.3 => fun( arg )=2.197
<type 'function'> : <function <lambda> at 0xb7662bc4>
arg=1.3 => fun( arg )=2.197
<type 'function'> : <function <lambda> at 0xb7662844>
arg=1.3 => fun( arg )=2.197

Ещё более отчётливо это проявляется в Python версии 3, в которой всё является классами (в том числе, и
целочисленная переменная), а функции являются объектами программы, принадлежащими к классу
:

$ python3 func.py 1.3
<class 'function'> : <function pow3 at 0xb74542ac>
arg=1.3 => fun( arg )=2.1970000000000005
<class 'function'> : <function <lambda> at 0xb745432c>
arg=1.3 => fun( arg )=2.1970000000000005
<class 'function'> : <function <lambda> at 0xb74542ec>
arg=1.3 => fun( arg )=2.1970000000000005

Примечание. Существуют ещё 2 типа объектов, допускающих функциональный вызов —
функциональный метод класса и функтор, о которых мы поговорим позже.

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

  • динамически изменять в ходе выполнения;
  • встраивать в более сложные структуры данных (коллекции);
  • передавать в качестве параметров и возвращаемых значений и т.д.

На этом (манипуляции с функциональными объектами как с объектами данных) и базируется функциональное
программирование. Python, конечно, не является настоящим языком функционального программирования, так,
для полностью функционального программирования существуют специальные языки: Lisp, Planner, а из более
свежих: Scala, Haskell. Ocaml, … Но в Python можно «встраивать» приёмы функционального программирования в
общий поток императивного (командного) кода, например, использовать методы, заимствованные из
полноценных функциональных языков. Т.е. «сворачивать» отдельные фрагменты императивного кода (иногда
достаточно большого объёма) в функциональные выражения.

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

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

print (  )

В результате запуска получаем:

$ python funcp.py

Variable-length arguments

You may need to process a function for more arguments than you specified while defining the function. These arguments are called variable-length arguments and are not named in the function definition, unlike required and default arguments.

Syntax for a function with non-keyword variable arguments is this −

def functionname( *var_args_tuple ):
   "function_docstring"
   function_suite
   return 

An asterisk (*) is placed before the variable name that holds the values of all nonkeyword variable arguments. This tuple remains empty if no additional arguments are specified during the function call. Following is a simple example −

#!/usr/bin/python

# Function definition is here
def printinfo( arg1, *vartuple ):
   "This prints a variable passed arguments"
   print "Output is: "
   print arg1
   for var in vartuple:
      print var
   return;

# Now you can call printinfo function
printinfo( 10 )
printinfo( 70, 60, 50 )

When the above code is executed, it produces the following result −

Output is:
10
Output is:
70
60
50

Процедуры

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

Рассмотрим синтаксис процедуры на примере:

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

Решение: 

def Err():  # определение процедуры
  print ( "Ошибка: неверные данные" ) 
n = int ( input('введите положительное число') ) 
if n < : 
  Err() # вызов процедуры
  • Процедура — вспомогательный алгоритм, выполняющий некоторые действия.
  • Это поименованный фрагмент программы, который можно вызвать.
  • Процедура должна быть определена к моменту её вызова. Определение процедуры начинается со служебного слова def.
  • Вызов процедуры осуществляется по ее имени, за которым следуют круглые скобки, например, Err().
  • В одной программе может быть сколько угодно много вызовов одной и той же процедуры.
  • Использование процедур сокращает код и повышает удобочитаемость.

Процедура с параметрами

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

Пример: Написать процедуру, которая печатает 60 раз указанный символ (введенный с клавиатуры), каждый с новой строки.

Решение: 

1
2
3
4
5
def printChar(s):
   for i in range(60):
      print (s) 
sim = input('введите символ')
printChar(sim)
  • Глобальная переменная — если ей присвоено значение в основной программе (вне процедуры).
  • Локальная переменная (внутренняя) известна только на уровне процедуры, обратиться к ней из основной программы и из других процедур нельзя.
  • Параметры процедуры — локальные переменные. В программе s — локальная переменная.

Задание Python 3_0:
Создать процедуру, которая вычисляет разность двух вводимых пользователем числа. Выполнить задание двумя способами: 1) процедура без параметров: числа — глобальные переменные, определенные в основной программе; 2) процедура с параметрами: числа — параметры процедуры.

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

Примеры использования локальных и глобальных переменных:

1
2
3
4
x = 3 # глобальная переменная
def pr(): # процедура без параметров
  print (x) # вывод значения глобальной переменной
pr()
1
2
3
4
5
x = 3  # глобальная переменная
def pr(a): # процедура с параметром
  a = 4 # локальная переменная
  print (a) # 4
pr(x) # передача параметра глобальной переменной (3)

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

1
2
3
4
5
6
x = 3 # глобальная переменная
def pr(): # процедура без параметров
  global x
  x = 1
  print (x) # вывод измененного значения глобальной переменной (1)
pr(x)

Задание Python 3_1:
Напишите процедуру, которая выводит на экран в столбик все цифры переданного ей числа, начиная с последней:

число: 4673
результат:
3
7
6
4

Задание Python 3_2:
Напишите процедуру, которая выводит на экран все делители переданного ей числа (в одну строчку).

Задание Python 3_3:
Составить программу с процедурой для вычисления степени числа (входные параметры: число и степень).

Задание Python 3_4:
Напишите процедуру, которая принимает параметр – натуральное число N – и выводит первые N чисел Фибоначчи.

Defining a Function

You can define functions to provide the required functionality. Here are simple rules to define a function in Python.

  • Function blocks begin with the keyword def followed by the function name and parentheses ( ( ) ).

  • Any input parameters or arguments should be placed within these parentheses. You can also define parameters inside these parentheses.

  • The first statement of a function can be an optional statement — the documentation string of the function or docstring.

  • The code block within every function starts with a colon (:) and is indented.

  • The statement return exits a function, optionally passing back an expression to the caller. A return statement with no arguments is the same as return None.

Несколько простейших примеров

Выполним несколько простейших трансформаций привычного императивного кода (командного,
операторного) для превращения его отдельных фрагментов в функциональные. Сначала заменим операторы
ветвления логическими условиями, которые за счёт «отложенных» (lazy, ленивых) вычислений позволяют
управлять выполнением или невыполнением отдельных ветвей кода. Так, императивная конструкция:

if <условие>:
    <выражение 1>
else:
    <выражение 2>

— полностью эквивалентна следующему функциональному фрагменту (за счёт «отложенных» возможностей
логических операторов и ):

# функция без параметров:
lambda: ( <условие> and <выражение 1> ) or ( <выражение 2> )

В качестве примера снова используем вычисление факториала. В листинге 4 приведен функциональный код
для вычисления факториала (файл fact1.py в архиве python_functional.tgz в
разделе «Материалы для скачивания»):

Листинг 4. Операторное (императивное) определение факториала
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
 
def factorial( n ):
    if n == 1: return 1
    else: return n * factorial( n - 1 )

if len( sys.argv ) > 1:
    n = int( sys.argv )
else:
    n = int( input( "число?: " ) )

print( "n={} => n!={}".format( n, factorial( n ) ) )

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

  • определение функции факториала:

    factorial = lambda x: ( ( x == 1 ) and 1 ) or x * factorial( x - 1 )
  • запрос на ввод значения аргумента с консоли терминала:

    arg = lambda : ( len( sys.argv ) > 1 and int( sys.argv ) ) or \
                     int( input( "число?: " ) )
    n = arg()

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

factorial = factorial = lambda z: reduce( lambda x, y: x * y, range( 1, z + 1 ) )

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

n = ( lambda : ( len( sys.argv ) > 1 and int( sys.argv ) ) or \
                 int( input( "число?: " ) ) )()

Наконец, можно заметить, что присвоение значения переменной
требуется только для её использования в вызове для вывода
этого значения. Если мы откажемся и от этого ограничения, то всё приложение выродится в один
функциональный оператор (см. файл fact4.py в архиве python_functional.tgz в
разделе «Материалы для скачивания»):

from sys import *
from functools import reduce
print( 'вычисленный факториал = {}'.format( \
         ( lambda z: reduce( lambda x, y: x * y, range( 1, z + 1 ) ) ) \
             ( ( lambda : ( len( argv ) > 1 and int( argv ) ) or \
                 int( input( "число?: " ) ) )() ) ) )

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

$ python3 fact4.py
число?: 5
вычисленный факториал = 120

Читается ли этот код (файл fact4.py) лучше, чем императивная запись (файл fact1.py)? Скорее нет, чем да. В
чём же тогда его достоинство? В том, что при любых изменениях окружающего его кода,
нормальная работа этого фрагмента сохранится, так как отсутствует риск побочных эффектов
из-за изменения значений используемых переменных.

Циклы

Перед тем, как мы ознакомимся с тем, как работает range(), нам нужно взглянуть на то, как работают циклы. Циклы — это ключевая концепция компьютерных наук. Если вы хотите стать хорошим программистом, умение обращаться с циклами — это важнейший навык, который стоит освоить.

Рассмотрим пример цикла for в Python:

Python

captains =

for captain in captains:
print(captain)

1
2
3
4

captains=’Janeway’,’Picard’,’Sisko’

forcaptain incaptains

print(captain)

Выдача выглядит следующим образом:

Python

Janeway
Picard
Sisko

1
2
3

Janeway
Picard
Sisko

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

Хотя Star Trek — отличная тема и все такое, вам может быть нужен более сложный цикл, чем список капитанов. Иногда вам нужно просто выполнить часть кода определенное количество раз. Циклы могут помочь вам с этим.

Попробуйте запустить следующий код с числами, кратными трем:

Python

numbers_divisible_by_three =

for num in numbers_divisible_by_three:
quotient = num / 3
print(f»{num} делится на 3, результат {int(quotient)}.»)

1
2
3
4
5

numbers_divisible_by_three=3,6,9,12,15

fornum innumbers_divisible_by_three

quotient=num3

print(f»{num} делится на 3, результат {int(quotient)}.»)

Выдача цикла будет выглядеть следующим образом:

Python

3 делится на 3, результат 1.
6 делится на 3, результат 2.
9 делится на 3, результат 3.
12 делится на 3, результат 4.
15 делится на 3, результат 5.

1
2
3
4
5

3делитсяна3,результат1.

6делитсяна3,результат2.

9делитсяна3,результат3.

12делитсяна3,результат4.

15делитсяна3,результат5.

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

Теперь, когда вы знакомы с циклами поближе, посмотрим, как вы можете использовать range() для упрощения жизни.

Keyword arguments

Keyword arguments are related to the function calls. When you use keyword arguments in a function call, the caller identifies the arguments by the parameter name.

This allows you to skip arguments or place them out of order because the Python interpreter is able to use the keywords provided to match the values with parameters. You can also make keyword calls to the printme() function in the following ways −

#!/usr/bin/python

# Function definition is here
def printme( str ):
   "This prints a passed string into this function"
   print str
   return;

# Now you can call printme function
printme( str = "My string")

When the above code is executed, it produces the following result −

My string

The following example gives more clear picture. Note that the order of parameters does not matter.

#!/usr/bin/python

# Function definition is here
def printinfo( name, age ):
   "This prints a passed info into this function"
   print "Name: ", name
   print "Age ", age
   return;

# Now you can call printinfo function
printinfo( age=50, name="miki" )

When the above code is executed, it produces the following result −

Name:  miki
Age  50

The Anonymous Functions

These functions are called anonymous because they are not declared in the standard manner by using the def keyword. You can use the lambda keyword to create small anonymous functions.

  • Lambda forms can take any number of arguments but return just one value in the form of an expression. They cannot contain commands or multiple expressions.

  • An anonymous function cannot be a direct call to print because lambda requires an expression

  • Lambda functions have their own local namespace and cannot access variables other than those in their parameter list and those in the global namespace.

  • Although it appears that lambda’s are a one-line version of a function, they are not equivalent to inline statements in C or C++, whose purpose is by passing function stack allocation during invocation for performance reasons.

Default arguments

A default argument is an argument that assumes a default value if a value is not provided in the function call for that argument. The following example gives an idea on default arguments, it prints default age if it is not passed −

#!/usr/bin/python

# Function definition is here
def printinfo( name, age = 35 ):
   "This prints a passed info into this function"
   print "Name: ", name
   print "Age ", age
   return;

# Now you can call printinfo function
printinfo( age=50, name="miki" )
printinfo( name="miki" )

When the above code is executed, it produces the following result −

Name:  miki
Age  50
Name:  miki
Age  35

Заключение

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

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

Похожие темы

  • Девид Мертц, Очаровательный Python: Функциональное программирование на языке Python, Часть 1
  • Девид Мертц, Очаровательный Python: Еще о функциональном программировании на Python, Часть 2
  • David Mertz, Charming Python: Functional programming in Python, Part 3
  • Тонкости использования языка Python: Часть 2. Типы данных.
  • Тонкости использования языка Python: Часть 4. Параллельное исполнение.
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *