Домашно 1 - "Пет дребни функции"
„ Програмиране с Python“, ФМИ
22.03.2010
Функциите
def one(seq): ...
def inject(fun): ...
def unfold(initial, step, condition, skip = None): ...
def theta(fun, *lists): ...
def memoize(fun): ...
Общи забележики
- Когато искате да сложите коментар във функция - правете го като:
def func(seq):
"""This function does something"""
one
- Условие
def one(seq): ...
- Функция
one
, която връща истина когато в seq
има точно един елемент, който се оценява като истина.
one
- Реализация
def one(seq):
matched = False
for item in seq:
if item:
if not matched:
matched = True
else:
return False
return matched
one
- Забележки (1)
- Променливи като
res
, temporary
, flag
и т.н. не са добра идея.
- За
one
подходяща е matched
, matches
.
- Променливи с имена на български (китайски|виетнамски|суахили) не са четими за някои хора.
- Не хващайте ZeroDivisionError.
one
- Забележки (2)
if ((bool)(condition) == True): ...
if condition: ...
inject
- Условие
def inject(fun): ...
- Функция от по-висок ред, която свежда списък до единствена стойност.
inject
- Реализация
def inject(fun):
def injector(seq, initial = None):
seq_iter = iter(seq)
result = initial if initial != None else next(seq_iter)
for n in seq_iter:
result = fun(result, n)
return result
return injector
unfold
- Условие
def unfold(initial, step, condition, skip = None): ...
- Функция, която трансформира единична стойност в списък.
unfold
- Реализация
def unfold(initial, step, condition, skip = None):
current = initial
while condition(current):
if skip == None or not skip(current):
yield current
current = step(current)
unfold
- Ваши Реализации
def unfoldrec(initial,step,condition,skip=None):
current = initial
if not condition(current):
return []
elif skip==None or not skip(current):
return [current] + unfold(step(current),step,condition,skip)
else:
return unfold(step(current),step,condition,skip)
def unfold(initial,step,condition,skip=None):
'''But the recursion was so pretty'''
...
theta
- Условие
def theta(fun, *lists): ...
- Функция, която приема предикат и няколко списъка.
- Връща подмножеството на декартовото произведение на тези списъци, за което предикатът се оценява като истина.
- Резултатът трябва да е списък (поредица) от n-орки. Редът им няма значение.
theta
- Реализация
def theta(fun, *lists):
return filter(lambda args: fun(*args), product(*lists))
theta
- Реализация
def theta(fun, *lists):
return filter(lambda args: fun(*args), product(*lists))
def product(first, *other):
if other:
for n in first:
for nested in product(*other):
yield tuple([n] + list(nested))
else:
for n in first: yield (n,)
theta
- Ваши реализации (1)
def theta(predicate, *sequences):
import itertools
l=itertools.product(*sequences)
return list(filter(lambda x:predicate(*x),l))
theta
- Ваши реализации (2)
def theta(predicate, *sequences):
temp, result = [[]], []
for seq in sequences:
# Cartesian product
temp = [x+[y] for x in temp for y in seq]
for product in temp:
if predicate(*product): result.append( tuple(product) )
return result
theta
- Забележки
- Ползвайте
filter
, когато е удобно
memoize
- Условие
def memoize(fun): ...
- Връща двойка функции:
- функция
memoize
, връщаща мемоизиращ вариант на fun.
- функция, която ще ни дава графиката на запомнените стойности (реда няма значение).
memoize
- Реализация
def memoize(fun):
cache = {}
def memoized(*args):
if args in cache: return cache[args]
result = cache[args] = fun(*args)
return result
return memoized, lambda:(args + (result,) for args, result in cache.items())
memoize
- Ваши Реализации
def memoize(fun):
cache = {}
graph = set()
def memoizedfun(*args, **kwargs):
nonlocal graph
args += tuple(kwargs.values())
if args in graph:
return cache[args]
else:
result = fun(*args)
cache[args] = result
graph |= {args + (result,)}
return result
return memoizedfun, lambda: graph
memoize
- Забележки
- Не ползвайте глобална променлива за кеша. Всяка фунцкия трябва да има собстен кеш.
- По принцип избягвайте глобални променливи.