2

I am reading Python Crash Course, and the question is given as

9-5. Login Attempts: Add an attribute called login_attempts to your User class from Exercise 9-3 (page 166). Write a method called increment_ login_attempts() that increments the value of login_attempts by 1.

Write another method called reset_login_attempts() that resets the value of login_ attempts to 0.

Make an instance of the User class and call increment_login_attempts() several times. Print the value of login_attempts to make sure it was incremented properly, and then call reset_login_attempts(). Print login_attempts again to make sure it was reset to 0.

I defined the class as

class User():
    def __init__(self, first_name, last_name, gender, age):
        """
        User inputs
        """
        self.first_name = first_name
        self.last_name = last_name
        self.gender = gender
        self.age = age
        self.login_attempts = 0

    def describe_user(self):
        """
        Printing the users information
        """
        print("User Name: ", self.first_name)
        print("Last Name: ", self.last_name)
        print("Gender: ", self.gender)
        print("Age: ", self.age)

    def increment_login_attempts(self):
        '''
        Increment the login attempts one by one, each time users try to enter
        '''
        self.login_attempts += 1
        print("You have tried logging in", self.login_attempts, "times")

    def reset_login_attempts(self):
        '''
        Resetting the logging attempts
        '''
        self.login_attempts = 0
        print("Login Attempt has set to ", self.login_attempts)

user = User("Sean", "Dean", "Male", 19)
user.describe_user()
user.increment_login_attempts()
user.increment_login_attempts()
user.increment_login_attempts()
user.increment_login_attempts()
user.reset_login_attempts()

Now my problem is something like this,

When I only write,

user = User("Sean", "Dean", "Male", 19)
user.describe_user()
user.increment_login_attempts()

it prints

User Name:  Sean
Last Name:  Dean
Gender:  Male
Age:  19
You have tried logging in 1 times

and that is fine, but when I close the code and re-run it, it again prints the same thing. So apparently, I am changing the self.login_attempts only in that instance (i.e., when I run the code) but when I close the code and re-run, it goes back to 0

My question is, why is this so ?

I mean its clear that each time I run the program the self.login_attempts is set to 0, but it seems somewhat strange to me.

Is there a way to modify the code such that, in each re-run self.login_attempts will increment by itself, without calling the user.increment_login_attempts() multiple times ? In other words is there a real way of changing the value of the self.login_attempts = 0 , just by re-running the code?

martineau
  • 119,623
  • 25
  • 170
  • 301
Arman Çam
  • 115
  • 7
  • 2
    "and that is fine, but when I close the code and re-run it, it again prints the same thing. So apparently, I am changing the self.login_attempts only in that instance (i.e., when I run the code) but when I close the code and re-run, it goes back to 0" *of course*. Once your process terminates, *everything is reclaimed*. You have everything in memory, you haven't actually persisted anything. This is a pretty fundamental aspect of how a program works. – juanpa.arrivillaga Dec 04 '20 at 20:30
  • maintain a database if you want to save user login attemps – sahasrara62 Dec 04 '20 at 20:52

1 Answers1

1

When you change the attributes of an existing instance of a class, the change is only to what's in memory at that moment. If you want to make it persistent, so it's the same then next time you run the program, you need save the data somewhere like a file or database.

You can save it in a file by using Python built-in pickle module, which makes doing so fairly easy. (See my answer to the question Saving an Object (Data persistence) for more details.)

One way to make use of it with your class would be a to create a users dictionary that mapped user names to instances of the User class. In the example below the user's first and last names are joined together to form keys for the dictionary.

class User():
    ...  # Your class.


if __name__ == '__main__':

    # Example of creating, reading, and updating a persistent users dictionary.

    from pathlib import Path
    import pickle

    db_filepath = Path('user_database.pkl')

    if not db_filepath.exists():
        # Create database and add one user for testing.
        users = {}
        user = User("Sean", "Dean", "Male", 19)
        users[', '.join((user.last_name, user.first_name))] = user

        with open(db_filepath, 'wb') as outp:
            pickle.dump(users, outp, -1)

        print('database created with one user:')
        user.describe_user()


    if db_filepath.exists():
        # Read existing database.
        with open(db_filepath, 'rb') as inp:
            users = pickle.load(inp)

        print('Users in existing database:')
        for user in users.values():
            user.describe_user()

        print()
        user = users['Dean, Sean']  # Assume user exists.
        if user.login_attempts > 3:  # Reset if more than 3.
            print('Resetting Sean Dean\'s login attempts.')
            user.reset_login_attempts()

        print('Incrementing Sean Dean\'s login attempts.')
        user.increment_login_attempts()

        # Update the database file.
        with open(db_filepath, 'wb') as outp:
            pickle.dump(users, outp, -1)

martineau
  • 119,623
  • 25
  • 170
  • 301