Создать атрибут функции python

Магия Python

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

вторник, 8 декабря 2015 г.

Расширенные возможности функций: возврат значений при помощи «yield», атрибуты функций, лямбда функции

yield

До сих пор мы говорили о том, что функция может возвращать свое значение при помощи инструкции «return», которая возвращает какое-то значение и прекращает работу функции.
Есть еще один способ возвращать значения из функции — так называемая «отложенная точка возврата». Делается это при помощи инструкции «yield», возвращающей итератор функции при вызове которого, значения будут отдаваться нам по одному за вызов. Фактически итератор функции будет выполнять участок функции до инструкции «yield», возвращать значение и приостанавливать функцию до ее следующего вызова, запоминая ее текущее состояние. Немного запутано, но далее мы разберем каждый шаг объявления и выполнения функций с использованием «yield».

Для начала объявим функцию, которая будет принимать список чисел и возвращать список ччисел помноженных на 2:
>>> def mul(l):
. templ = []. for i in l:
. templ.append(i*2)
. return templ
.
>>> mul([1,2,3,4,5])
[2, 4, 6, 8, 10]>>>

Эта функция более чем очевидна. А теперь напишем подобную функцию с использованием «yield»:
>>> def mul(l):
. for i in l:
. yield i*2
.
>>>

Теперь тело нашей функции состоит только из цикла фор, в котором при помощи инструкции «yield», мы возвращаем текущий элемент «*2». При вызове этой функции, нам вернется некий объект, который будет иметь свойство объекта-итератора, а это означает, что у этого объекта будет метод «next()».
>>> mul([1,2,3,4,5]) # Вернет итератор функции

>>> mymul = mul([1,2,3,4,5]) # Присваиваем возвращаемый объект переменной «mymul»
>>> mymul

>>> dir(mymul)
[‘__class__’, ‘__delattr__’, ‘__doc__’, ‘__format__’, ‘__getattribute__’, ‘__hash__’, ‘__init__’, ‘__iter__’, ‘__name__’, ‘__new__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’, ‘close’, ‘gi_code’, ‘gi_frame’, ‘gi_running’, ‘next’, ‘send’, ‘throw’]>>> mymul.next()
2
>>> mymul.next()
4
>>> mymul.next()
6
>>> mymul.next()
8
>>> mymul.next()
10
>>> mymul.next()
Traceback (most recent call last):
File » «, line 1, in
StopIteration
>>>

При каждом вызове метода «next()», наша функция выполняет цикл итерации по переданному списку, возвращает нам текущий элемент помноженный на 2, приостанавливает функцию запоминая ее состояние и при следующем вызове метода «next()» начинает работу с того места, на котором функция была приостановлена. Стоит помнить, что «yield» не возвращает нам объект в котором заложен готовый список элементов, а в действительности выполняет функцию каждый раз при обращении к методу «next()». Это легко проверить, переписав нашу функцию следующим образом:
>>> def mul(l):
. for i in l:
. print u»Выполняем цикл»
. yield i*2
.
>>> mymul = mul([1,2,3,4,5])
>>> mymul.next()
Выполняем цикл
2
>>> mymul.next()
Выполняем цикл
4
>>> mymul.next()
Выполняем цикл
6
>>> mymul.next()
Выполняем цикл
8
>>> mymul.next()
Выполняем цикл
10
>>> mymul.next()
Traceback (most recent call last):
File » «, line 1, in
StopIteration
>>>

Тут видно, что при вызове «next()», выполняется очередной шаг итерации циклом «for». Когда функция доходит до своего логического завершения, мы получаем исключение «StopIteration».
В одной функции могут последовательно выполняться несколько инструкций «yield».
>>> def mul(l):
. for i in l:
. print u’Выполняется первый цикл’
. yield i*2
. print u’Был выполнен первый цикл, приступаем к циклу два.’
. for i in l:
. print u’Выполняется второй цикл’
. yield i*5
. print u’конец функции’
.
>>>
>>> mymul = mul([1,2,3,4,5])
>>> mymul.next()
Выполняется первый цикл
2
>>> mymul.next()
Выполняется первый цикл
4
>>> mymul.next()
Выполняется первый цикл
6
>>> mymul.next()
Выполняется первый цикл
8
>>> mymul.next()
Выполняется первый цикл
10
>>> mymul.next()
Был выполнен первый цикл, приступаем к циклу два.
Выполняется второй цикл
5
>>> mymul.next()
Выполняется второй цикл
10
>>> mymul.next()
Выполняется второй цикл
15
>>> mymul.next()
Выполняется второй цикл
20
>>> mymul.next()
Выполняется второй цикл
25
>>> mymul.next()
конец функции
Traceback (most recent call last):
File » «, line 1, in
StopIteration
>>>

Функции с применением инструкции «Yield», удобно использовать, когда есть необходимость обработать очень большой массив данных, что займет много времени, или функция должна вернуть настолько большой список, что возникнет исключение переполненности памяти. В таком случае, мы можем возвращать необходимые значения через «yield», что поможет нам доставать необходимые значения постепенно и убережет нас от переполненности памяти.

Читайте также:  Types of lists java

Атрибуты функций

Функция в Python — это объект, она имеет имя-переменную, которая ссылается на объект функции и где в виде кортежа в круглых скобочках (), мы передаем аргументы в функцию. Определенные свойства объектов в языке Python, позволяют нам объявлять переменные(атрибуты) в области видимости объектов и использовать их в работе. Синтаксис следующий: «имя_функции.имя_переменной = значение». Соответственно, обратившись к переменной в области видимости функции, мы можем получить ее значение.
Давайте рассмотрим следующий пример:
>>> def myfunc():
. return 0
.
>>> dir(myfunc)
[‘__call__’, ‘__class__’, ‘__closure__’, ‘__code__’, ‘__defaults__’, ‘__delattr_
_’, ‘__dict__’, ‘__doc__’, ‘__format__’, ‘__get__’, ‘__getattribute__’, ‘__globa
ls__’, ‘__hash__’, ‘__init__’, ‘__module__’, ‘__name__’, ‘__new__’, ‘__reduce__’
, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subcla
sshook__’, ‘func_closure’, ‘func_code’, ‘func_defaults’, ‘func_dict’, ‘func_doc’
, ‘func_globals’, ‘func_name’]>>>

Мы создали функцию, которая возвращает 0, но это сейчас неважно. При помощи функции «dir()», мы получили доступ к атрибутам функции. Кпримеру «func_name», Хранит в себе название функции. «func_dict», хранит в себе объявленные переменные в области видимости объекта, в виде словаря, где ключ — название переменной, значение — значение переменной, на это мы посмотрим далее. Давайте объявим несколько переменных в области видимости объекта нашей функции:
>>> myfunc.var = «Ok»
>>> myfunc.num = 5
>>> myfunc.lst = [1,2,3,4,5]>>> #воспользуемся атрибутом «func_dict»
.
>>> dir(myfunc) # мы можем наблюдать объявленные переменные
[‘__call__’, ‘__class__’, ‘__closure__’, ‘__code__’, ‘__defaults__’, ‘__delattr_
_’, ‘__dict__’, ‘__doc__’, ‘__format__’, ‘__get__’, ‘__getattribute__’, ‘__globa
ls__’, ‘__hash__’, ‘__init__’, ‘__module__’, ‘__name__’, ‘__new__’, ‘__reduce__’
, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subcla
sshook__’, ‘func_closure’, ‘func_code’, ‘func_defaults’, ‘func_dict’, ‘func_doc’
, ‘func_globals’, ‘func_name’, ‘lst’, ‘num’, ‘var’]>>> myfunc.func_dict # Получаем словарь с объявленными переменными

>>> myfunc.var
‘Ok’
>>> myfunc.num
5
>>> myfunc.lst
[1, 2, 3, 4, 5]>>>

Как мы можем это использовать? Кпримеру, можно сохранять некоторые возвращаемые значения для их просмотра и дальнейшего использования, это делает функцию в Python еще более автономной. Давайте напишем функцию, которая будет возвращать сумму двух чисел и сохранять результат, как атрибут своего объекта:
>>> def plus(a, b):
. plus.result = a+b
. return a+b
.
>>> plus(2,3)
5
>>> plus.result
5
>>> plus(5,6)
11
>>> plus.result
11
>>>

Теперь после каждого вызова функции «plus()», ее результат будет не только возвращаться, но и сохраняться в переменной «result», в пространстве имен объекта функции.
Давайте объявим функцию «plus()», которая будет сохранять в своих атрибутах: список всех результатов, которые возвращались при ее вызове, количество вызовов функции и список кортежей, где будут попарно храниться переданные при вызове значения:
>>> def plus(a, b):
. try:
. plus.result.append(a+b) # При первом вызове, атрибута «result» несуществует и будет возбуждено исключение «AttributeError»
. except AttributeError:
. plus.result = [a+b] # Если возбуждено исключение, объявляем атрибут в пространстве имени функции
. # Далее происходит также
. try:
. plus.count += 1
. except AttributeError:
. plus.count = 1
. try:
. plus.arguments.append((a,b))
. except AttributeError:
. plus.arguments = [(a,b)]. return a+b
.
>>> plus(5,4)
9
>>> plus(3,4)
7
>>> plus(2,2)
4
>>> plus(7,12)
19
>>> plus.func_dict

Читайте также:  Java static class logger

>>> plus.count
4
>>> plus.arguments
[(5, 4), (3, 4), (2, 2), (7, 12)]>>> plus.result
[9, 7, 4, 19]>>>

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

(lambda) функции

Помимо «создания», функций при помощи инструкции «def», в Python, существуют так называемые «неименованные» функции, или лямбда функции. Лямбда функции записываются в одну строку, что позволяет очень гибко встраивать их в те места, где нам необходим определенный функционал и избавляет от излишнего написания кода, Т.К. Позволяет избежать объявления функции при помощи инструкции «def». Объявление такой функции, происходит при помощи инструкции «lambda», после которой следуют локальный переменные аргументов, двоеточие «:» и выражение:
lambda x, y: x*y
Это создаст объект функции, которая принимает в себя 2 аргумента и возвращает результат перемножения переданных значений. Как видно, функция действительно не имеет имени и для того, чтобы иметь возможность взаимодействовать с ней, нам необходимо присвоить лямбда функцию, какой-то переменной:
>>> mylambda = lambda x, y: x*y
>>> mylambda
at 0x01DD8BB0>
>>> mylambda(2,3)
6
>>> mylambda(3,3)
9
>>>

Не стоит искать в лямбда функциях какую-то магию, в действительности, это простая функция, которая позволяет объявить себя в одну строку, что бывает удобно. Кпримеру, мы можем объявить несколько лямбда функций в списке:
>>> lambdalist = [lambda x, y: x*y, lambda x, y: x+y, lambda x, y: x**y]>>> lambdalist[0](3,3)
9
>>> lambdalist[1](3,3)
6
>>> lambdalist[2](3,3)
27
>>>

Элементами списка являются лямбда функции, затем они вызываются по индексам и им передаются значения. Впринципе, мы могли бы справится с этой задачей и при помощи «def» функций, но кода было бы гораздо больше:
>>> def mult(x, y):
. return x*y
.
>>> def add(x,y):
. return x+y
.
>>> def pow(x, y):
. return x**y
.
>>> funclist = [mult, add, pow]>>> funclist[0](3,3)
9
>>> funclist[1](3,3)
6
>>> funclist[2](3,3)
27
>>>

Скорее всего, более плотное знакомство с лямбда функциями произойдет во время изучения создания графических интерфейсов в Python.

Источник

Оцените статью