Для выполнения задания найди ссылку-приглашение в онлайн чате, получи доступ к репозиторию с файлом-заготовкой и заполни пропуски в нём. Фиксируй изменения (делай коммиты) после решения каждой задачи. Оставь название файла неизменным, иначе робот-проверятель не найдёт твои ответы. Отправить решения на GitHub нужно до истечения установленного срока. |
Изменчивые функции
Вопрос 1
Определи функцию make_counter
, которая возвращает функцию counter
, которая принимает строку и возвращает количество вызовов этой функции с заданной строкой.
def make_counter():
"""Возвращает функцию counter.
>>> c = make_counter()
>>> c('a')
1
>>> c('a')
2
>>> c('b')
1
>>> c('a')
3
>>> c2 = make_counter()
>>> c2('b')
1
>>> c2('b')
2
>>> c('b') + c2('b')
5
"""
"*** ТВОЙ КОД ЗДЕСЬ ***"
Вопрос 2
Функция make_fib
должна вернуть функцию, которая при первом вызове возвращает первое число Фибоначчи, при втором — второе и так далее.
Используй инструкцию nonlocal .
|
def make_fib():
"""Возвращает функцию, возвращающую следующее число Фибоначчи при каждом вызове.
>>> fib = make_fib()
>>> fib()
0
>>> fib()
1
>>> fib()
1
>>> fib()
2
>>> fib()
3
>>> fib2 = make_fib()
>>> fib() + sum([fib2() for _ in range(5)])
12
"""
"*** ТВОЙ КОД ЗДЕСЬ ***"
Вопрос 3
В лекции было показано, как с помощью функций создавать изменяющиеся объекты. Вот, например, функция make_withdraw
, которая создает функцию, позволяющую снимать деньги со счёта.
def make_withdraw(balance):
"""Возвращает функцию withdraw с начальным балансом.
>>> withdraw = make_withdraw(1000)
>>> withdraw(100)
900
>>> withdraw(100)
800
>>> withdraw(900)
'Недостаточно средств'
"""
def withdraw(amount):
nonlocal balance
if amount > balance:
return 'Недостаточно средств'
balance = balance - amount
return balance
return withdraw
Напиши новую версию make_withdraw
, возвращающую функцию для снятия денег со счета с парольной защитой. То есть make_withdraw
теперь должна принимать также и пароль (строка) в дополнение к начальному балансу. Возвращаемая функция должна принимать два аргумента: сумму для снятия и пароль.
Защищенная паролем функция withdraw
должна выполнять исключительно только те снятия, в которых указан правильный пароль. При получении неправильного пароля функция должна:
-
Сохранить этот неправильный пароль в списке
-
Вернуть строку 'Неправильный пароль'.
Если функция снятия была вызвана три раза с неверными паролями p1
, p2
и p3
, тогда она блокируется — то есть все последующие вызовы должны выводить:
"Твой аккаунт заблокирован. Попытки входа: ['p1', 'p2', 'p3']"
Неправильные пароли могут быть одинаковыми или отличаться:
def make_withdraw(balance, password):
"""Возвращает защищённую паролем функцию withdraw.
>>> w = make_withdraw(100, 'hax0r')
>>> w(25, 'hax0r')
75
>>> error = w(90, 'hax0r')
>>> error
'Недостаточно средств'
>>> error = w(25, 'hwat')
>>> error
'Неверный пароль'
>>> new_bal = w(25, 'hax0r')
>>> new_bal
50
>>> w(75, 'a')
'Неверный пароль'
>>> w(10, 'hax0r')
40
>>> w(20, 'n00b')
'Неверный пароль'
>>> w(10, 'hax0r')
"Твой аккаунт заблокирован. Попытки входа: ['hwat', 'a', 'n00b']"
>>> w(10, 'l33t')
"Твой аккаунт заблокирован. Попытки входа: ['hwat', 'a', 'n00b']"
>>> type(w(10, 'l33t')) == str
True
"""
"*** ТВОЙ КОД ЗДЕСЬ ***"
Вопрос 4
Представь, что банковская система должна поддерживать объединённые счета. Определи функцию make_joint
, которая принимает 3 аргумента:
-
защищенную паролем функцию
withdraw
; -
пароль от функции
withdraw
; -
дополнительный пароль для доступа к счету.
Функция make_joint
должна возвращать функцию withdraw
, которая разрешает доступ к счету как со старым, так и с новым паролями. Обе функции списывают средства с одного счёта. При суммарном трёхкратном вводе неправильного пароля счёт должен заблокироваться.
Решение невелико (менее 10 строк кода) и не содержит строковых переменных. Идея в том, чтобы вызывать Используй |
def make_joint(withdraw, old_password, new_password):
"""Возвращает защищенную паролем функцию, которая присоединяется к существующей функции withdraw с новым паролем.
>>> w = make_withdraw(100, 'hax0r')
>>> w(25, 'hax0r')
75
>>> make_joint(w, 'my', 'secret')
'Неверный пароль'
>>> j = make_joint(w, 'hax0r', 'secret')
>>> w(25, 'secret')
'Неверный пароль'
>>> j(25, 'secret')
50
>>> j(25, 'hax0r')
25
>>> j(100, 'secret')
'Недостаточно средств'
>>> j2 = make_joint(j, 'secret', 'code')
>>> j2(5, 'code')
20
>>> j2(5, 'secret')
15
>>> j2(5, 'hax0r')
10
>>> j2(25, 'password')
'Неверный пароль'
>>> j2(5, 'secret')
"Твой аккаунт заблокирован. Попытки входа: ['my', 'secret', 'password']"
>>> j(5, 'secret')
"Твой аккаунт заблокирован. Попытки входа: ['my', 'secret', 'password']"
>>> w(5, 'hax0r')
"Твой аккаунт заблокирован. Попытки входа: ['my', 'secret', 'password']"
>>> make_joint(w, 'hax0r', 'hello')
"Твой аккаунт заблокирован. Попытки входа: ['my', 'secret', 'password']"
"""
"*** ТВОЙ КОД ЗДЕСЬ ***"
Генераторы
Вопрос 5
Определи функцию generate_paths
, которая принимает дерево t
и значение x
и возвращает генератор, возвращающий все возможные пути от корня t
к узлу со значением x
. Каждый путь должен быть представлен списком значений из соответствующих вершин. Возвращать пути можно в любом порядке.
def generate_paths(t, x):
"""Возвращает генератор всех возможных путей от корня t до значения x в виде списков.
>>> t1 = tree(1, [tree(2, [tree(3), tree(4, [tree(6)]), tree(5)]), tree(5)])
>>> print_tree(t1)
1
2
3
4
6
5
5
>>> next(generate_paths(t1, 6))
[1, 2, 4, 6]
>>> path_to_5 = generate_paths(t1, 5)
>>> sorted(list(path_to_5))
[[1, 2, 5], [1, 5]]
>>> t2 = tree(0, [tree(2, [t1])])
>>> print_tree(t2)
0
2
1
2
3
4
6
5
5
>>> path_to_2 = generate_paths(t2, 2)
>>> sorted(list(path_to_2))
[[0, 2], [0, 2, 1, 2]]
"""
"*** ТВОЙ КОД ЗДЕСЬ ***"