How to fix a higher-order function to simulate a joint bank account?

761 views Asked by At

Q.

Suppose that our banking system requires the ability to make joint accounts. Define a function make_joint that takes three arguments.

  1. A password-protected withdraw function,

  2. The password with which that withdraw function was defined, and

  3. A new password that can also access the original account.

The make_joint function returns a withdraw function that provides additional access to the original account using either the new or old password. Both functions draw down the same balance. Incorrect passwords provided to either function will be stored and cause the functions to be locked after three wrong attempts.

Hint: The solution is short (less than 10 lines) and contains no string literals! The key is to call withdraw with the right password and interpret the result. You may assume that all failed attempts to withdraw will return some string (for incorrect passwords, locked accounts, or insufficient funds), while successful withdrawals will return a number.

Use type(value) == str to test if some value is a string:

Solution

def make_withdraw(balance, password):
    """Return a password-protected withdraw function.

    >>> w = make_withdraw(100, 'hax0r')
    >>> w(25, 'hax0r')
    75
    >>> w(90, 'hax0r')
    'Insufficient funds'
    >>> w(25, 'hwat')
    'Incorrect password'
    >>> w(25, 'hax0r')
    50
    >>> w(75, 'a')
    'Incorrect password'
    >>> w(10, 'hax0r')
    40
    >>> w(20, 'n00b')
    'Incorrect password'
    >>> w(10, 'hax0r')
    "Your account is locked. Attempts: ['hwat', 'a', 'n00b']"
    >>> w(10, 'l33t')
    "Your account is locked. Attempts: ['hwat', 'a', 'n00b']"
    """
    incorrect_password_list = []
    count = 0
    def withdraw(amount, input_passwd):
        nonlocal count
        if count < 3:
            if input_passwd == password:
                nonlocal balance
                if  amount < balance:
                    balance -= amount
                    return balance          
                else:
                    return "Insufficient funds"
            else:
                nonlocal incorrect_password_list
                incorrect_password_list.append(input_passwd)
                count += 1              
                return "Incorrect password"
        else:
            return "Your account is locked. Attempts: ['{0}', '{1}', '{2}']".format(incorrect_password_list[0], incorrect_password_list[1], incorrect_password_list[2])
    return withdraw




def make_joint(withdraw, old_passwd, new_passwd):
    """
    >>> w = make_withdraw(100, 'hax0r')
    >>> w(25, 'hax0r')
    75
    >>> make_joint(w, 'my', 'secret')
    'Incorrect password'
    >>> j = make_joint(w, 'hax0r', 'secret')
    >>> w(25, 'secret')
    'Incorrect password'
    >>> j(25, 'secret')
    50
    >>> j(25, 'hax0r')
    25
    >>> j(100, 'secret')
    'Insufficient funds'
    """
    value = withdraw(0, old_passwd)
    if type(value) == str:
        return "Incorrect password"
    else:
        def joint_withdraw(balance, input_passwd):
            if (input_passwd ==  old_passwd) or (input_passwd ==  new_passwd):
                return withdraw(balance, old_passwd)
        return joint_withdraw

My question:

Apart from test cases mentioned in docstring of above solution make_joint, below additional test cases are yet to pass, Please provide an hint to modify make_joint to satisfy these given additional test cases(below).

    >>> j2 = make_joint(j, 'secret', 'code')
    >>> j2(5, 'code')
    20
    >>> j2(5, 'secret')
    15
    >>> j2(5, 'hax0r')
    10

    >>> j2(25, 'password')
    'Incorrect password'
    >>> j2(5, 'secret')
    "Your account is locked. Attempts: ['my', 'secret', 'password']"
1

There are 1 answers

2
200_success On

Let's just focus on these lines:

def joint_withdraw(balance, input_passwd):
    if (input_passwd ==  old_passwd) or (input_passwd ==  new_passwd):
        return withdraw(balance, old_passwd)

What happens when the input_passwd is neither the old_passwd nor the new_passwd? Your function gives does nothing, and gives no response.

Note that you already have code to respond to incorrect passwords. How can you define joint_withdraw to reuse that functionality?

Fix that problem in the way that I hinted, and you should be able to get j2(5, 'hax0r') to work.