# Функции как равноправные объекты¶

In [1]:
def f():
print(1)

g = f
g()

1


## svn.py¶

In [2]:
import sys

def checkout(*args):
print('checkout{}'.format(args))

def commit(*args):
print('commit{}'.format(args))

commands = {
'checkout': checkout,
'co': checkout,
'commit': commit,
'ci': commit
}

cmd, *args = 'commit', 'arg1', 'arg2' #sys.argv[1:]
commands[cmd](*args)

commit('arg1', 'arg2')


# Передача функций в качестве аргументов в другие функции¶

## Аналог filter¶

In [1]:
def filter(function, iterable):
for e in iterable:
if function(e):
yield e

def is_even(number):
return number % 2 == 0

a = [1, 2, 3, 4, 5]
for e in filter(is_even, a):
print(e)

2
4

In [2]:
a = range(6)
for e in filter(is_even, a):
print(e)

0
2
4


## Неполный аналог map¶

In [1]:
def map(function, iterable):
for e in iterable:
yield function(e)

def square(x):
return x ** 2

for e in map(square, [1, 2, 3]):
print(e)

1
4
9


## Аналог map¶

In [2]:
def map(function, *iterables):
iters = [iter(iterable) for iterable in iterables]
while True:
try:
args = [next(it) for it in iters]
yield function(*args)
except StopIteration:
break

return a + b

for e in map(add, [1, 2, 3], [4, 5, 6]):
print(e)

5
7
9


## lambda¶

In [1]:
for e in map(lambda a, b: a + b, [1, 2, 3], [4, 5, 6]):
print(e)

5
7
9


# Функции, которые возвращают другие функции¶

In [1]:
def add(a, b):
return a + b

def partial(function, *args):
def new_function(*more_args):
all_args = args + more_args
return function(*all_args)
return new_function

inc(4)

Out[1]:
5
In [2]:
import functools
import operator

print(inc(4))

5


## Кеширующий декоратор¶

In [1]:
import timeit

def caching(function):
computed_results = {}
def new_function(*args):
if args not in computed_results:
computed_results[args] = function(*args)
return computed_results[args]
return new_function

def fibonacci_number(i):
if i == 0 or i == 1:
return 1
return fibonacci_number(i - 1) + fibonacci_number(i - 2)

print(timeit.timeit('fibonacci_number(30)', number=3, setup='from __main__ import fibonacci_number'))
fibonacci_number = caching(fibonacci_number)
print(timeit.timeit('fibonacci_number(30)', number=3, setup='from __main__ import fibonacci_number'))

2.3664230789872818
5.887000588700175e-05

In [2]:
import timeit

def caching(function):
computed_results = {}
def new_function(*args):
if args not in computed_results:
computed_results[args] = function(*args)
return computed_results[args]
return new_function

@caching
def fibonacci_number(i):
if i == 0 or i == 1:
return 1
return fibonacci_number(i - 1) + fibonacci_number(i - 2)

print(timeit.timeit('fibonacci_number(30)', number=3, setup='from __main__ import fibonacci_number'))

5.275104194879532e-05


# Что можно узнать о функции?¶

In [1]:
def f(x):
print(x)

print(f.__name__)
g = f
print(g.__name__)
g = lambda: 1
print(g.__name__)
print(f.__module__)

f
f
<lambda>
__main__


## docstrings¶

In [2]:
def caching(function):
'''Caching decorator for functions with positional arguments.'''

computed_results = {}
def new_function(*args):
if args not in computed_results:
computed_results[args] = function(*args)
return computed_results[args]
new_function.__name__ = function.__name__
new_function.__doc__ = function.__doc__
return new_function

@caching
def fibonacci_number(i):
'''Function for calculating i-th Fibonacci number.'''

if i == 0 or i == 1:
return 1
return fibonacci_number(i - 1) + fibonacci_number(i - 2)

In [3]:
import caching
help(caching) #    $pydoc caching  Help on module caching: NAME caching FUNCTIONS caching(function) Caching decorator for functions with positional arguments. fibonacci_number(*args) Function for calculating i-th Fibonacci number. FILE /Users/tswr/python/caching.py  In [4]: from IPython.display import HTML with open('caching.html') as f: #$ pydoc -w caching
h

Out[4]:
Python: module caching

 Functions caching(function)Caching decorator for functions with positional arguments. fibonacci_number(*args)Function for calculating i-th Fibonacci number.

## code object¶

In [5]:
caching.caching.__code__.co_code

Out[5]:
b'i\x00\x00\x89\x00\x00\x87\x00\x00\x87\x01\x00f\x02\x00d\x01\x00d\x02\x00\x86\x00\x00}\x01\x00\x88\x01\x00j\x00\x00|\x01\x00_\x00\x00\x88\x01\x00j\x01\x00|\x01\x00_\x01\x00|\x01\x00S'
In [6]:
import dis
dis.dis(caching.caching)

  4           0 BUILD_MAP                0
3 STORE_DEREF              0 (computed_results)

12 BUILD_TUPLE              2
15 LOAD_CONST               1 (<code object new_function at 0x10eb93420, file "/Users/tswr/python/caching.py", line 5>)
21 MAKE_CLOSURE             0
24 STORE_FAST               1 (new_function)

36 STORE_ATTR               0 (__name__)

48 STORE_ATTR               1 (__doc__)

54 RETURN_VALUE

In [7]:
import inspect
sig = inspect.signature(caching.caching)
print(sig)

(function)

In [8]:
print(sig.parameters)

OrderedDict([('function', <Parameter at 0x10eb7e1f8 'function'>)])

In [9]:
print(inspect.getsource(caching.caching))

def caching(function):
'''Caching decorator for functions with positional arguments.'''

computed_results = {}
def new_function(*args):
if args not in computed_results:
computed_results[args] = function(*args)
return computed_results[args]
new_function.__name__ = function.__name__
new_function.__doc__ = function.__doc__
return new_function