Search code examples
pythonpython-3.xpython-class

Instantiating classes with user input


I have just started learning about classes. In the examples that I'm learning I notice how everything that gets instantiated is hardcoded into the examples. I wanted to try and figure out if I could instantiate without having to do this, by means of user input. In line 74/75 my expectation is that print(RecordID_map_PilotID[valUE].flownhours) prints me the number of hours I have chosen to log for a specific instance. Instead I'm confronted with the following pesky error:

Traceback (most recent call last):
  File "oop_test.py", line 74, in <module>
    RecordID_map_PilotID[valUE].recordflytime(loghours)
AttributeError: 'str' object has no attribute 'recordflytime'

Can anyone please help me understand why what I intend Python to do doesn't actually work? Thank you!

PilotID_ClassValCalls = {}
RecordID_map_PilotID = {}
class PilotRecord:
    department = "Aviation"
    asset = "Employee"
    assetcategory = "FTE"
    flownhours = 0

    def __init__(self, pilotid, name, age, licensestatus, licenseexpiration, shiptype, callsign, flownhours):

        self.pilotid = pilotid
        self.name = name
        self.age = age
        self.licensestatus = licensestatus
        self.licenseexpiration = licenseexpiration
        self.shiptype = shiptype
        self.callsign = callsign
        self.flownhours = flownhours

    def __str__(self):

        return f"{self.pilotid} has an {self.licensestatus} license with an expiration date of {self.licenseexpiration} with the following callsigns:\n {self.callsign} ."

    def recordflytime(self, hours):
        self.flownhours = self.flownhours + hours

def Adding_Pilot_Records(): #This definitions created new pilot records and instantiates a new object for each pilot rcord that is created. In addition memory values are stored in Dict

    add_records_number = int(input("How many pilot records would you like to add? "))

    for eachrecord in range(add_records_number):


        record_store = [input("Please provide pilot ID: "), input("Please provide pilot Name: "), int(input("Please provide pilot Age: ")),
        input("Please provide pilot licensestatus: "), input("Please provide pilot licenseexpiration: "), input("Please provide pilot shiptype: "), input("Please provide pilot callsign: "), 0]

        PilotID_ClassValCalls.update({eachrecord + 1 : record_store[0]})
        RecordID_map_PilotID.update({PilotID_ClassValCalls[eachrecord+1]: record_store[0]}) 

        PilotID_ClassValCalls[eachrecord+1] =  PilotRecord(record_store[0], record_store[1], record_store[2], record_store[3], record_store[4], record_store[5], record_store[6], record_store[7])

while True == True:
    print("Hello, Welcome to the PILOT RECORD DATABASE\n",
    "What would you like to do with the Records?:\n\n",
    " \t1 - \"Add\"\n",
    " \t2 - \"Log\"\n",
    " \t3 - \"Delete\"\n",
    " \t4 - \"Quit\"\n")

    userchoice = str(input().lower().strip())

    try:

        if userchoice == "1" or userchoice == "add":
            Adding_Pilot_Records()
            continue

        elif userchoice == "2" or userchoice == "log":

            while userchoice == "2" or userchoice == "log":

                pickarecord = str(input("Which Record ID would you like to create a log for? ")).split()
                pickarecord_yesno = input(f"Selected Record >>> {RecordID_map_PilotID[pickarecord[0]]}, Is this the correct record? [Y] [N] [Quit]").upper().split()
                userchoice = ""
                if pickarecord_yesno[0] == "Q" or pickarecord_yesno[0] == "QUIT":
                    break
                elif pickarecord_yesno[0] == "Y" or pickarecord_yesno[0] == "YES":
                    userchoice = ""
                    loghours = int(input(f"How many hours would you like to log?"))
                    pickarecord = str(pickarecord[0])
                    for record, valUE in RecordID_map_PilotID.items():
                        if pickarecord in valUE:
                            RecordID_map_PilotID[valUE].recordflytime(loghours)
                            print(RecordID_map_PilotID[valUE].flownhours)

                elif pickarecord_yesno[0] == "N" or pickarecord_yesno == "NO":
                    userchoice = "2"
                    continue





        elif userchoice == "3" or userchoice == "delete":
            continue

        elif userchoice == "4" or userchoice == "quit":
            break

    except ValueError:
            print("Sorry an Error has occurred")

Solution

  • This is the line causing the error:

    RecordID_map_PilotID[valUE].recordflytime(loghours)
    

    You're trying to call .recordflytime() on RecordID_map_PilotID[valUE]. But RecordID_map_PilotID is a dictionary of type str -> str, so RecordID_map_PilotID[valUE] references a string and strings don't have .recordflytime() methods.

    I can tell it's a string, because this line is the only line modifying it:

    RecordID_map_PilotID.update({PilotID_ClassValCalls[eachrecord+1]: record_store[0]})
    

    So, you're updating one dict with another, with a single key/value pair, the key being PilotID_ClassValCalls[eachrecord+1] and the value record_store[0]. PilotID_ClassValCalls is filled similarly, and its value also typically is record_store[0]. And you fill record store with the result of a call to input(), which is a string.

    I would suggest you read some examples on object-oriented programming in Python - I think you're trying to do 'by hand' what is better done with the specific data structures and methods that exist for it in Python.

    More generally, it's a good idea to separate the structures that hold and operate on data from the code that gets an processes input. After all, you want to manipulate these objects with direct user input now, but what if you save stuff out to a file and read it back later? Or perhaps call your code from a web page? You'd want to use the same classes, but without the direct calls to input() resulting in your code expecting input on the console.