Search code examples
pythonpython-3.xoopself

How to fix "name 'self' is not defined" error in python?


I'm trying to learn python OOP, I am stuck with the error below.

Exception has occurred: NameError
name 'self' is not defined
  File "/home/khalid/Desktop/MiniProject3/test1.py", line 27, in <module>
    login = first_class (self.Bank_Users.keys(), self.Bank_Users.values())
  File "/home/khalid/anaconda3/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/home/khalid/anaconda3/lib/python3.7/runpy.py", line 96, in _run_module_code
    mod_name, mod_spec, pkg_name, script_name)
  File "/home/khalid/anaconda3/lib/python3.7/runpy.py", line 263, in run_path
    pkg_name=pkg_name, script_name=fname)

I've tried to search for similar problems that may have been solved, but I couldn't find a way to get past this error.

class first_class(object):

    def __init__(self, UserName, Password, Bank_Users):
        self.UserName = UserName
        self.Password = Password
        self.Bank_Users = {"Aldo": "1234"}


    def login_or_exit(self):

        while True:
            print("Please Enter User Name")
            self.UserName = input(">> ")
            print("Please Enter Password")
            self.Password = input(">> ")

            if self.UserName in self.Bank_Users.keys() and self.Password in self.Bank_Users.values():
                print("Logging into", self.UserName)

            else:
                print("Unsuccesful!!")

login = first_class (self.Bank_Users.keys(), self.Bank_Users.values())
login.login_or_exit()

Solution

  • Doing this correctly might look like:

    class BankLoginSystem(object):
        def __init__(self, bank_users):
            self.bank_users = bank_users
            self.logged_in_user = None
        def login_or_exit(self):
            while True:
                print("Please Enter User Name")
                attempted_user = input(">> ")
                print("Please Enter Password")
                attempted_password = input(">> ")
                if attempted_password == self.bank_users.get(attempted_user):
                    self.logged_in_user = attempted_user
                    print("Success!!")
                    return
                else:
                    print("Unsuccesful!!")
    
    # the user database is independent of the implementation
    bank_users = { "Aldo": "1234" }
    
    login = BankLoginSystem(bank_users)
    login.login_or_exit()
    print("Logged in user is: %s" % login.logged_in_user)
    

    Note that we aren't taking the username and password as initialization arguments to the object -- since an object can have multiple users logged in over the course of its lifetime, doing so doesn't make sense.

    Similarly, things that should be kept private (like attempted passwords) we aren't storing in class member variables, but keeping strictly as locals so they don't leak out-of-scope. (In a real system you'd want your password database to have salted hashes, not real passwords, containing the damage if the password database itself leaks).

    BTW, note that generally speaking, combining your I/O logic with your backend storage representation is a bad idea -- typically, you want to have pure objects modeling your domain separate and distinct from whatever interaction with users takes place.