Практика 6 — Комбинаторы и функциональный стиль
Функции высшего порядка, декораторы и функциональные структуры данных.
Edit on GitHubИсточник:
pr_Python/pr_Python/pract6.ipynb
1.1. (уровень сложности: низкий)
Напишите функцию deriv для приближенного вычисления производной в заданной точке.
Пример работы:
deriv(lambda x: x ** 3)(5) 75.00014999664018
def deriv(f, h=0.0001):
def fprime(x):
return (f(x + h) - f(x)) / h
return fprime
result = deriv(lambda x: x ** 3)(5)
print(result)Вывод:
75.001500009790331.2. (уровень сложности: средний)
Создайте вариант именованного кортежа с помощью ФВП. Классы и готовые структуры данных (словари, кортежи и так далее) использовать нельзя.
Примеры работы:
p1 = person(name='Иван', age=20) p2 = replace(replace(p1, 'name', 'Алексей'), 'age', 21) get(p1, 'name'), get(p1, 'age') ('Иван', 20) get(p2, 'name'), get(p2, 'age') ('Алексей', 21)
def person(**kwargs):
def get(obj, key):
return obj["data"][key] if key in obj["data"] else None
def replace(obj, name, new_value):
obj[name] = new_value
return obj
return {
"data": kwargs,
"get": get,
"replace": replace,
}
# Примеры использования
p1 = person(name="Иван", age=20)
p2 = person(replace(p1, 'name', 'Алексей'), 'age', 21)
print(person.get(p1, "name"), person.get(p1, "age"))
print(person.get(p2, "name"), person.get(p2, "age"))1.3. (уровень сложности: низкий)
Реализуйте рекурсивное вычисление факториала в виде выражения. Необходимо это сделать без использования именованных функций, переменных (в том числе без имени факториала) и присваиваний.
(lambda f: (lambda x: f(lambda k: x(x)(k)))(lambda x: f(lambda k: x(x)(k)))(lambda f: lambda n: 1 if n == 0 else n * f(f)(n - 1))(10)1.4. (уровень сложности: низкий)
Создайте декоратор io, который задает функции для получения входных аргументов и вовращения результата.
Примеры:
@io(input, input, input, print) def f1(x, y, z): return x + y + z
f1() one two three onetwothree @io(lambda: random.random(), lambda: random.random(), lambda x: x) def f2(x, y): return x * y
f2() 0.19896827110422532
import random
def io(*inputs_and_output):
def decorator(func):
def wrapper(*args):
input_values = [input_func() for input_func in inputs_and_output[:-1]]
result = func(*input_values)
output_func = inputs_and_output[-1]
output_func(result)
return wrapper
return decorator
@io(input, input, input, print)
def f1(x, y, z):
return x + y + z
@io(lambda: random.random(), lambda: random.random(), lambda x: x)
def f2(x, y):
return x * y1.5. (уровень сложности: низкий)
Создайте декоратор класса @collect, который собирает все создаваемые объекты класса в единый список. К классу добавляется метод get_objects, который выдает этот список.
Пример:
@collect class C1: pass
a = C1() b = C1() c = C1()
C1.get_objects() [, , ]
def collect(cls):
cls._objects = []
def wrapper(*args, **kwargs):
obj = cls.__new__(cls)
obj.__init__(*args, **kwargs)
cls._objects.append(obj)
return obj
cls.__new__ = wrapper
def get_objects():
return cls._objects
cls.get_objects = get_objects
return cls
@collect
class MyClass:
pass- Работа со списками в функциональном стиле Создайте тип данных односвязный список с помощью ФВП. При создании списка нельзя использовать классы, готовые списки, кортежи и так далее.
Добавьте ряд операций в функциональном стиле.
def create_node(value):
return {"value": value, "next": None}
def prepend(node, value):
new_node = create_node(value)
new_node["next"] = node
return new_node
def append(node, value):
if node is None:
return create_node(value)
current = node
while current["next"] is not None:
current = current["next"]
current["next"] = create_node(value)
return node
def find(node, value):
current = node
while current is not None:
if current["value"] == value:
return current
current = current["next"]
return None
def print_list(node):
current = node
while current is not None:
print(current["value"], end=" ")
current = current["next"]
print()
# Пример использования
my_list = None
my_list = prepend(my_list, 3)
my_list = prepend(my_list, 2)
my_list = append(my_list, 4)
my_list = append(my_list, 5)
print_list(my_list)
# Поиск элемента
element = find(my_list, 4)
if element:
print("Found:", element["value"])
else:
print("Not Found")Вывод:
2 3 4 5
Found: 42.1. (уровень сложности: высокий)
Создайте функцию pair(head, tail), которая порождает элемент списка. Не используйте ветвления. Создайте также функции head(lst) (возвращает значение головы списка) и tail(lst) (возвращает хвост списка).
# Функция pair создает элемент списка
def pair(value, next_node=None):
return lambda selector: value if selector == "value" else next_node
# Функция head возвращает значение головы списка
def head(lst):
return lst("value")
# Функция tail возвращает хвост списка
def tail(lst):
return lst("tail")
# Пример использования
list_node = pair(1, pair(2, pair(3, pair(4))))
print("Head node value:", head(list_node))
tail_node = tail(list_node)
print("Tail node value:", head(tail_node))Вывод:
Head node value: 1
Tail node value: 22.2. (уровень сложности: средний)
Создайте функцию make_list(*args), которая создает список на основе аргументов.
def make_list(*args):
if not args:
return None
def pair(value, next_node=None):
return lambda selector: value if selector == "value" else next_node
list_node = None
current_node = None
for arg in reversed(args):
if list_node is None:
list_node = pair(arg)
current_node = list_node
else:
new_node = pair(arg, current_node)
current_node = new_node
return current_node
# Пример использования
my_list = make_list(1, 2, 3, 4, 5)
current_node = my_list
while current_node:
print(current_node("value"))
current_node = current_node("tail")Вывод:
1
2
3
4
5