19 ноября 2012 г.

Возможности функций


Расширенные возможности функций

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

• Взаимодействие: для передачи значений функции используйте аргументы, для возврата результатов  – инструкцию return.

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

• Взаимодействие: не воздействуйте на изменяемые аргументы, если вызывающая программа не предполагает этого.

• Связность: каждая функция должна иметь единственное назначение.

• Размер: каждая функция должна иметь относительно небольшой размер.

• Взаимодействие: избегайте непосредственного изменения переменных в другом модуле.



















Немного о классах в Python ООП:
Так как язык Python объектно ориентированный (ООП), а ООП часто зависит от функций и классов, тогда стоит рассмотреть одну из возможностей класса.
Классы в языке Python зависят от изменения передаваемого изменяемого объекта  – функции воздействуют на атрибуты аргумента self, получаемого автоматически, изменяя информацию о его состоянии (например, self.name = ‘bob’). Кроме того, когда нет возможности использовать классы, часто наилучший способ сохранения информации о состоянии между вызовами функций представляют глобальные переменные в модуле.

Язык Python поддерживает рекурсивные функции – функции, которые могут вызывать сами себя, прямо или косвенно, образуя цикл.
Вычисляем сумму с применением рекурсии:
>>> def mysum(L):
...  if not L:
...    return 0
...  else:
...    return L[0] + mysum(L[1:]) # Вызывает себя саму

>>> mysum([1, 2, 3, 4, 5])
15

Альтернативные решения:

def mysum(L):
    return 0 if not L else L[0] + mysum(L[1:]) # Трехместный оператор

def mysum(L): # Суммирует любые типы
    return L[0] if len(L) == 1 else L[0] + mysum(L[1:]) 
    #предполагает наличие  хотя бы одного значения

def mysum(L):
    first, *rest = L
    return first if not rest else first + mysum(rest)
# Использует расширенную операцию присваивания 
# последовательностей

Результаты:
>>> mysum([1]) # mysum([]) будет завершаться ошибкой в 2 последних функциях
1
>>> mysum([1, 2, 3, 4, 5])
15
>>> mysum((‘s’, ‘p’, ‘a’, ‘m’)) # Но они могут суммировать данные любых типов
‘spam’
>>> mysum([‘spam’, ‘ham’, ‘eggs’])
‘spamhameggs’
-----------------------------------------------------------------

Обработка структур данных:
Рекурсия является мощным инструментом для работы с различными структурами данных. Далее мы рассмотрим пример для нахождение суммы всех чисел определенной структуры, которая состоит из вложенных списков.
Пример:
[1, [2, [3, 4], 5], 6, [7, 8]] # Произвольно вложенные списки
def sumtree(L):
    tot = 0
    for x in L: # Обход элементов одного уровня
        if not isinstance(x, list):
           tot += x # Числа суммируются непосредственно
        else:
           tot += sumtree(x) # Списки обрабатываются рекурсивными 
    return tot               #вызовами   
L = [1, [2, [3, 4], 5], 6, [7, 8]] # Произвольная глубина
                                   # вложения
print(sumtree(L)) # Выведет 36
# Патологические случаи
print(sumtree([1, [2, [3, [4, [5]]]]])) # Выведет 15 (центр тяжести справа)
print(sumtree([[[[[1], 2], 3], 4], 5])) # Выведет 15 (центр тяжести слева)
Функции в  языке Python гораздо более гибкие. Функции в языке Python являются полноценными объектами, хранящими в  памяти все, чем они владеют. Кроме того, они свободно могут передаваться между частями программы и вызываться косвенно. У них также есть некоторые особенности, которые имеют мало общего с вызовами, – атрибуты и аннотации.

Косвенный вызов функций:
В  имени, которое используется в  инструкции def, нет ничего уникального: это всего лишь переменная, которая создается в текущей области видимости, как если бы оно стояло слева от знака =. После того как инструкция def будет выполнена, имя функции представляет собой всего лишь ссылку на объект – ее можно присвоить другим именам и вызывать функцию по любому из них (не только по первоначальному имени):
>>> def echo(message): # Имени echo присваивается объект функции
...     print(message) 
... 
>>> echo(‘Direct call’) 
Direct call 
>>> x = echo 
>>> x(‘Indirect call!’) 
Indirect call 
-----------------------------------------------------------------

Функции легко можно передавать другим функциям в  виде аргументов:
>>> def indirect(func, arg):
...     func(arg) # Вызов объекта добавлением ()
...
>>> indirect(echo, ‘Argument call!’) # Передача функции в функцию
Argument call!
-----------------------------------------------------------------

Также возможно наполнять структуры данных функциями, как если бы они были простыми числами или строками. В этом нет ничего необычного, так как составные типы объектов могут содержать объекты любых типов:
>>> schedule = [ (echo, ‘Spam!’), (echo, ‘Ham!’) ]
>>> for (func, arg) in schedule:
...      func(arg) # Вызов функции, сохраненной в контейнере
...
Spam!
Ham!
Выполняется обход списка schedule и  производится вызов функции echo с одним аргументом.
-----------------------------------------------------------------

Завершающий простой пример:
>>> def make(label): # Создает функцию, но не вызывает ее
...     def echo(message):
...         print(label + ‘:’ + message)
...     return echo
...
>>> F = make(‘Spam’) # Метка сохраняется во вложенной области видимости
>>> F(‘Ham!’)
# Вызов функции, созданной функцией make
Spam:Ham!
>>> F(‘Eggs!’)
Spam:Eggs!
-----------------------------------------------------------------

Комментариев нет:

Отправить комментарий