Problem 5: Protected Secret (100pts)
Problem
Write a function
protected_secretwhich takes in apassword,secret, andnum_attempts.
protected_secretshould return another function which takes in apasswordand printssecretif the password entered matches thepasswordgiven as an argument toprotected_secret. Otherwise, the returned function should print "INCORRECT PASSWORD". Afternum_attemptsincorrect passwords are used, the secret is locked forever and the function should print "SECRET LOCKED".For example:
编写一个函数 protected_secret,它接受一个 password(密码)、一个 secret(秘密)和一个 num_attempts(尝试次数)。
protected_secret 应该返回另一个函数,该函数接受一个 password,如果输入的密码与传递给 protected_secret 的密码参数匹配,则打印 secret。否则,返回的函数应该打印 "INCORRECT PASSWORD"(密码不正确)。在 num_attempts 次不正确的密码被使用后,秘密将被永久锁定,此时该函数应打印 "SECRET LOCKED"(秘密已锁定)。
例如:
>>> my_secret = protected_secret("sicp2025", "I love python.", 1)
>>> # Failed attempts: 0
>>> my_secret = my_secret("sicp2025")
I love python.
>>> # Failed attempts: 0
>>> my_secret = my_secret("abcdefg")
INCORRECT PASSWORD
>>> # Failed attempts: 1
>>> my_secret = my_secret("NanjingUniversity")
SECRET LOCKED
See the doctests for a detailed example.
请参阅文档测试(doctests)以获取详细示例。
def protected_secret(password, secret, num_attempts):
"""
Returns a function which takes in a password and prints the SECRET if the password entered matches
the PASSWORD given to protected_secret. Otherwise it prints "INCORRECT PASSWORD". After NUM_ATTEMPTS
incorrect passwords are entered, the secret is locked and the function should print "SECRET LOCKED".
>>> my_secret = protected_secret("correcthorsebatterystaple", "I love NJU", 2)
>>> # Failed attempts: 0
>>> my_secret = my_secret("hax0r_1")
INCORRECT PASSWORD
>>> # Failed attempts: 1
>>> my_secret = my_secret("correcthorsebatterystaple")
I love NJU
>>> # Failed attempts: 1
>>> my_secret = my_secret("hax0r_2")
INCORRECT PASSWORD
>>> # Failed attempts: 2
>>> my_secret = my_secret("hax0r_3")
SECRET LOCKED
>>> my_secret = my_secret("correcthorsebatterystaple")
SECRET LOCKED
"""
def get_secret(password_attempt):
"*** YOUR CODE HERE ***"
return get_secret
Hints
Hint: We recommend you using self-referencing functions (see page 15-16 of slides on Higher-Order Functions) to achieve this problem.
-
我们建议您使用自引用函数(请参阅高阶函数幻灯片第 15-16 页)来完成此问题。
-
失败次数 +1,相当于
num_attempts-1。 -
实测不在
"*** YOUR CODE HERE ***"内写一些语句也可以通过 OJ。但相关知识超纲了。
Solutions
num_attempts 既可以是能尝试的最大次数,也可以理解为剩余的尝试次数。
如果用户输错了密码,我们可以让剩余的尝试次数 -1。
我们可以通过返回这个函数自身的方法,来解决这个问题。
def protected_secret(password, secret, num_attempts):
def get_secret(password_attempt):
# 如果尝试次数为 0, 我们应该锁定这个秘密。
if (num_attempts == 0):
print("SECRET LOCKED")
return protected_secret("114514", "1919810", 0) # 彩蛋!
# 如果用户密码输对了,我们应该打印秘密后,让剩余的尝试次数不变。
elif (password_attempt == password):
print(secret)
return protected_secret(password, secret, num_attempts)
# 如果密码输错了,我们应该让剩余的尝试次数 -1。
else:
print("INCORRECT PASSWORD")
return protected_secret(password, secret, num_attempts - 1)
return get_secret
使用 nonlocal (修改了其他部分的代码,但是可以通过 OJ)
def protected_secret(password, secret, num_attempts):
# failed_attempts 存储了当前失败的次数。
# 它是一个非局部变量,将被内部函数修改。
failed_attempts = 0
def get_secret(password_attempt):
# 声明这个变量是 nonlocal,以便在内部函数中修改外部变量
nonlocal failed_attempts
# 检查是否已锁定
if failed_attempts >= num_attempts:
print("SECRET LOCKED")
return get_secret # 返回自身以保持链式调用的状态
# 检查密码是否正确
if password_attempt == password:
print(secret)
# 成功访问后,不用进行其他操作
else:
print("INCORRECT PASSWORD")
# 密码不正确,增加失败尝试次数
failed_attempts = failed_attempts + 1
# 无论成功还是失败,都返回自身以便下一次调用,例如 my_secret = my_secret("...")
return get_secret
return get_secret