Python Forum
Troubleshooting simple script and printing class objects
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Troubleshooting simple script and printing class objects
#1
Relatively new to Python, I’m learning to read, create, use and manipulate classes.

For practice I have begun to create a class tracking user input for a US PassPort application. In my script I have documented each code segment for readability. Here it is:
#!/usr/bin/env python3

# MIT License
# By Drone4four / Angeles4four and Daniel08 on GitHub

# The purpose of this script is to collect personal US citizen passport information

# General initilization of libraries which I may use down the road:
import random
import os

# Create a new object type called, PassPort:
class PassPort(object):

    # Initilization of special method, right?
    def __init__(self, first_name, middle_name, last_name, gender, YOB, iQ):

        # Universal class object attribute:
        species = 'homo-sapien'

        # Regular class objects:
        self.first_name = first_name
        self.middle_name = middle_name
        self.last_name = last_name
        self.gender = gender
        self.YOB = YOB # (Year of birth)
        self.iQ = iQ # (Inteligence Quotient)

    # Comparing the iQ variable among the entire citizenry:
    def iQcomparison():
        average = int(100)
        genius = int(75)
        if self.iQ < average:
            print(str("The citizen is less smart than average."))
        elif self.iQ > average:
            print(str("The citizen is smarter than average."))
        elif self.iQ <= genius:
            print(str("The citizen is among smartest of Americans."))

# Instance of PassPort:
citizen256032 = PassPort(first_name='Jon', middle_name='Ross', last_name='Dobbs', gender='male', YOB=int(1947), iQ=int(44))

# Prints specific instance to CLI (second format ), right?
print("The citizen's first name is {}. \n The citizen's middle name is {}. \n The citizen's last name is {}. \n The species of the citizen is {}.  \n The gender of the citizen is {}. \n The citizen was born in the year {}. \n And finally, the citizen has an iQ of {}." format(citizen256032.first_name, citizen256032.middle_name, citizen256032.last_name, citizen256032.species, citizen256032.gender, str(citizen256032.YOB), str(citizen256032.iQ)))

# and this iQ, as compared to other citizens, he there is a flippin {iQcomparison()}.")

# Prints specific instance to CLI (first format), right?
# print("The citizen's first name is" + citizen256032.first_name + ".  The citizen's middle name is" + citizen256032.middle_name + ".  The citizen's last name is " + citizen256032.last_name + "The citizen was born in the year " + str(citizen256032.YOB) + ".  And finally, " str(citizen256032.iQ) + ".")

'''
====== TO DO =======
* Prompt user for all his/her citizen information instead of feeding it in the script
* Rename file
* Have print statement print all the information into a flowing plain english sentence
'''
In my shell, it throws this output:
Output:
$ python3 main.py File "main.py", line 44 print("The citizen's first name is {}. \n The citizen's middle name is {}. \n The citizen's last name is {}. \n The species of the citizen is {}. \n The gender of the citizen is {}. \n The citizen was born in the year {}. \n And finally, the citizen has an iQ of {}." format(citizen256032.first_name, citizen256032.middle_name, citizen256032.last_name, citizen256032.species, citizen256032.gender, str(citizen256032.YOB), str(citizen256032.iQ))) ^ SyntaxError: invalid syntax $
I'm not sure what this shell output is trying to say. I’ve tried swapping out the str() for int() when referring to the last two class variables. I’ve also tried running the script with neither str() nor int(). Still throws an error. Any one here have an idea as to what is wrong with my program?

Here is my code on GitHub. I am accepting pull requests.

Thanks for your attention.
Reply
#2
Over 140 - Genius or near genius
not < 75
Reply
#3
So first and foremost, the problem with your program is a missing .

You wrote something like this:
>>> "Some string: {}"format("spam")
  File "<stdin>", line 1
    "Some string: {}"format("spam")
                          ^
SyntaxError: invalid syntax
>>>
Note the missing dot.
>>> "Some string: {}".format("spam")
'Some string: spam'
>>>
More than this though, the reason this error is so hard to see is the length of your lines.

Let's instead create a __str__ method for your class so we can print it directly.  Let's also write the print line a little more sanely:
class PassPort(object): 
    def __init__(self, first_name, middle_name, last_name, gender, YOB, iQ):
        self.species = 'homo-sapien'
        self.first_name = first_name
        self.middle_name = middle_name
        self.last_name = last_name
        self.gender = gender
        self.YOB = YOB # (Year of birth)
        self.iQ = iQ # (Inteligence Quotient)

    def __str__(self):
        template = ["The citizen's first name is {first_name}.",
            "The citizen's middle name is {middle_name}.",
            "The citizen's last name is {last_name}.",
            "The species of the citizen is {species}.",
            "The gender of the citizen is {gender}.",
            "The citizen was born in the year {YOB}.",
            "And finally, the citizen has an iQ of {iQ}."]
        return "\n".join(template).format(**vars(self))


def main():
    citizen256032 = PassPort('Jon', 'Ross', 'Dobbs', 'male', 1947, 44)
    print(citizen256032)
 

if __name__ == "__main__":
    main()
Note now we can now just directly say print(citizen256032).
Reply
#4
Thank you, thank you, @Mekire. This script runs perfectly. It's elegant too compared to mine. I can tell you have had some practice. I have some further questions about the logic of line 19. I will return here to this forum soon. Thanks again.

(Nov-05-2017, 12:33 AM)Larz60+ Wrote: Over 140 - Genius or near genius
not < 75
@Larz60+: Yes, genius IQ is above 140. You are right. But the concept behind the placeholder of my passport exercise involves the “Church of the SubGenius”, which is a tongue-in-cheek nonsense religion. According to our founder and cult leader, J. R. Dobbs considers genius to be below 75.
Reply
#5
ever watch Idiocracy: https://www.youtube.com/watch?v=BBvIweCIgwk
Reply
#6
Steve Carell! Looks like a funny movie.
Reply
#7
At line 19, I think I understand the logic of the first half: The method, __str__, returns a line break for each variable inside the template list, while also invoking the join function. Question #1: Is that correct or almost correct?

The second half of line 19 throws me off. How does the format function multiply the class variables exponentially (with ‘**’)? This question I’ve asked is sort of my feeble attempt at explaining it as best I can. Question #2: Can someone please explain the logic of the second half of line 19 of Mekire’s improved script?

Line 23 of Mekire’s script assigns the instances of all the class variables for the PassPort class. Question #3: If I wanted to now prompt the user in in my shell to ask for each variable, for example asking for the user’s first name to input into the first class variable instance, how do I do that? Here is my new script where I attempt to implement that feature (I am referring to line 23) :
class PassPort(object):
    def __init__(self, first_name, middle_name, last_name, gender, YOB, iQ):
        self.species = 'homo-sapien'
        self.first_name = first_name
        self.middle_name = middle_name
        self.last_name = last_name
        self.gender = gender
        self.YOB = YOB # (Year of birth)
        self.iQ = iQ # (Intelligence Quotient)

    def __str__(self):
        template = ["The citizen's first name is {first_name}.",
            "The citizen's middle name is {middle_name}.",
            "The citizen's last name is {last_name}.",
            "The species of the citizen is {species}.",
            "The gender of the citizen is {gender}.",
            "The citizen was born in the year {YOB}.",
            "And finally, the citizen has an iQ of {iQ}."]
        return "\n".join(template).format(**vars(self))

def main():
	# citizen256032 = PassPort('Jon', 'Ross', 'Dobbs', 'male', 1947, 44)
	citizen256032 = PassPort(first_name=input("What is your first name?"),'Ross', 'Dobbs', 'male', 1947, 44)
    print(citizen256032)

if __name__ == "__main__":
    main()
In my initial script I attempted to assess the iQ variable using some methods. Question #4: If I wanted to print a note below the iQ class instance under the __str__ method to indicate the status of the client's iQ (like if it is average, below average or genius), how could I do that better (than my attempt in my original post)?

Thanks for your attention.
Reply
#8
To answer your question #3 in reguards to your latest post (#7) I would made a loop
that inputs each value from the user into some temperary variable and then use that
to populate the citizen256032 instance. Here is some code I wrote that works
but leaves alot of room for improvement.

def main():
    # citizen256032 = PassPort('Jon', 'Ross', 'Dobbs', 'male', 1947, 44)
    # first, middle, last, gender, yob, iq
    # initalize a list with the default values, inputs will replace these
    person = ['Jon','Ross','Dobbs','male',1947,44]

    EOF = False;  #End of File, I use this as a flag to stop the while loop

    while not EOF:
        person[0] = input('First Name:')
        while not person[0].isalpha(): # Keep asking if input contains anything other than letters
            print('Please enter a valid first name')
            person[0] = input('First Name:')
        person[1] = input('Middle Name:')
        while not person[1].isalpha():
            print('Please enter a valid middle name')
            person[1] = input('Middle Name:')
        person[2] = input('Last Name:')
        while not person[2].isalpha():
            print('Please enter a valid last name')
            person[2] = input('Last Name:')
        print('Please select your gender\n')
        person[3] = int(input('\t0) Female\n\t1) Male\n'))
        while (person[3] not in range(0,2)):
            print('Please enter a value of either 0 or 1')
            person[3] = int(input('\t0) Female\n\t1) Male\n'))
        person[4] = int(input('What year were you born? (nnnn): '))
        while (person[4] not in range(1800,2999)):
            print('Please enter a four digit number')
            person[4] = int(input('What year were you born? (nnnn): '))
        person[5] = int(input('What is your IQ?: '))
        while (person[5] not in range(0,160)):
            print('Please enter a number between 0 and 160 inclusive')
            person[5] = int(input('What is your IQ? (0-160): '))
        EOF = True;

    if (person[3] == 0):
        gender = 'male'
    else:
        gender = 'female'

    citizen256032 = PassPort(person[0],person[1], person[2], gender, person[4], person[5])
    print(citizen256032)
Here is my explanation of what I have done

EOF is just what I use to mark the end of the while loop, so after all input is gathered I mark EOF as false thus causing the while loop to break.

person is a list which I populated with default values, that once the user enters their
values, gets replaced with the users repsonce. Its sole purpose is to store the data while it is being collected

I get input for each value and then each time I sanitize the input from the user to verify that it meets the basic expectations, for example a name should not contain numbers and a year of birth should not be a string. In this case isalpha() will return true if the value given contains only letters, but I want to know if the user did NOT enter a purely alphabetic string in such case I want to continue looping for input untill the condition fails, which in this case means they did enter what was expected

to force person[3], person[4] and person[5] values to be integers, I enclose the input inside int(). I then test these using a contriversal method wherre range returns a list of values in that range which are then checked against the input. This can be considered slow and it is probably faster to use something like (0 <= person[5] <= 160) to check if the value is within range.

Because I gather 1 for male and 0 for female, and your object requires a string, I use the finaly if else block to create a gender variable which is the expected string

I hope this makes some sence

Like I said there are probably better ways to do this, for example I could have written a function that does the job of asking for input untill a user enters all letters, instead of rewriting that code over and over again. Also this is aproaching database teritory where books on the subject of coding such a database in various languages have been written. In this case the user input is thrown into memory which is then not accessable after the script ends.

Hope this helped somewhat.
Reply
#9
Thank you very much, @knackwurstbagel. I appreciate your time and care helping me refine my script. You’ve effectively addressed my Question #3.

I think I understand the logic of your code, especially with the very helpful explanation you’ve provided.

I have made some ever so slight modifications, copied below. I changed the year range when we ask the user when s/he was born. I removed the outermost parentheses for the while loops (which are valid with or without the parentheses, I just removed some of them for my sake). I also added some line breaks between each of the list item variable declarations, also for readability. Your script runs perfectly as you've presented it. Again, I made these small cosmetic changes as just my personal take.
#!/usr/bin/env python3
 
# MIT License
# By Drone4four / Angeles4four and Daniel08 on GitHub
 
# The purpose of this script is to collect personal US citizen passport information
 
# General initilization of libraries which I may use down the road:

import random
import os
 
# Create a new object type called, PassPort:
class PassPort(object):
    def __init__(self, first_name, middle_name, last_name, gender, YOB, iQ):
        self.species = 'homo-sapien'
        self.first_name = first_name
        self.middle_name = middle_name
        self.last_name = last_name
        self.gender = gender
        self.YOB = YOB # (Year of birth)
        self.iQ = iQ # (Intelligence Quotient)
 
    def __str__(self):
        template = ["The citizen's first name is {first_name}.",
            "The citizen's middle name is {middle_name}.",
            "The citizen's last name is {last_name}.",
            "The species of the citizen is {species}.",
            "The gender of the citizen is {gender}.",
            "The citizen was born in the year {YOB}.",
            "And finally, the citizen has an iQ of {iQ}."]
        return "\n".join(template).format(**vars(self))
 
def main():
    # citizen256032 = PassPort('Jon', 'Ross', 'Dobbs', 'male', 1947, 44)
    # first, middle, last, gender, yob, iq
    # initalize a list with the default values, inputs will replace these
    person = ['Jon','Ross','Dobbs','male',1947,44]

    EOF = False;  #End of File, I use this as a flag to stop the while loop

    while not EOF:

        person[0] = input('First Name: ')
        while not person[0].isalpha(): # Keep asking if input contains anything other than letters
            print('Please enter a valid first name')
            person[0] = input('First Name: ')

        person[1] = input('Middle Name: ')
        while not person[1].isalpha():
            print('Please enter a valid middle name')
            person[1] = input('Middle Name: ')

        person[2] = input('Last Name:')
        while not person[2].isalpha():
            print('Please enter a valid last name')
            person[2] = input('Last Name: ')

        print('Please select your gender\n')
        person[3] = int(input('\t0) Female\n\t1) Male\n'))

        while person[3] not in range(0,2):
            print('Please enter a value of either 0 or 1')
            person[3] = int(input('\t0) Female\n\t1) Male\n'))

        person[4] = int(input('What year were you born? (nnnn): '))
        while (person[4] not in range(0,2018)):
            print('Please enter a four digit number')
            person[4] = int(input('What year were you born? (nnnn): '))

        person[5] = int(input('What is your IQ?: '))
        while (person[5] not in range(0,160)):
            print('Please enter a number between 0 and 160 inclusive')
            person[5] = int(input('What is your IQ? (0-160): '))

        EOF = True;

    if person[3] == 0:
        gender = 'male'
    else:
        gender = 'female'

    citizen256032 = PassPort(person[0],person[1], person[2], gender, person[4], person[5])
    print(citizen256032)
 
if __name__ == "__main__":
    main()
To better flush out what I was trying to ask in Question #4: What if I wanted to invoke a value judgement about some of the information entered by the user. Like for example depending on the iQ entered, the computer will return “You’re super smart!” (if the user inputs an IQ less than 85) or “Dunce!” (if the user’s iQ is above 130)?

How would making a comparison with other information in a database work? For example, how would a program be able to refer to survey results of the citizenry to claim something accurately statistical like: “1 in 182 male Canadians share your same first name (John)”?

Thanks again, knack, for going above and beyond.
Reply
#10
Consider writing an instance method which returns the data. Just for printing convenience. 

class PassPort(object):
    def __init__(self, first_name, middle_name, last_name, gender, YOB, iQ):
        self.species = 'homo-sapien'
        self.first_name = first_name
        self.middle_name = middle_name
        self.last_name = last_name
        self.gender = gender
        self.YOB = YOB # (Year of birth)
        self.iQ = iQ # (Intelligence Quotient)
    
    # the property decorator will make the function accesible as if it is a class attribute
    @propert
    def data(self):
        return (self.first_name, self.middle_name, self.last_name, self.gender, self.YOB, self.iQ)

person = ['Jon','Ross','Dobbs','male',1947,44]
obj = PassPort(*person)
Then, when you want to print it you can just:
print("First:\t{}\n \
Middle:\t{}\n \
Last:\t{}\n \
Gender:\t{}\n \
Birth:\t{}\n \
IQ:\t{}".format(*obj.data)) # instead of typing each class attr
Output:
First:    Jon Middle:    Ross Last:    Dobbs Gender:    male Birth:    1947 IQ:    44
Well, the output looks like this. The formatting is lost somewhere:
[Image: hnvm5r]
"As they say in Mexico 'dosvidaniya'. That makes two vidaniyas."
https://freedns.afraid.org
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  OBS Script Troubleshooting Jotatochips 0 252 Feb-10-2024, 06:18 PM
Last Post: Jotatochips
  How can I access objects or widgets from one class in another class? Konstantin23 3 929 Aug-05-2023, 08:13 PM
Last Post: Konstantin23
  Troubleshooting with PySpy Positron79 0 788 Jul-24-2022, 03:22 PM
Last Post: Positron79
  Simple Python script, path not defined dubinaone 3 2,654 Nov-06-2021, 07:36 PM
Last Post: snippsat
  Troubleshooting site packages ('h5py' to be specific) aukhare 2 1,955 Nov-02-2020, 03:04 PM
Last Post: snippsat
  Class objects Python_User 12 4,301 Aug-27-2020, 08:02 PM
Last Post: Python_User
  How to create and define in one line a 2D list of class objects in Python T2ioTD 1 1,986 Aug-14-2020, 12:37 PM
Last Post: Yoriz
  OOP hellp (simple class person) onit 4 2,488 Jul-14-2020, 06:54 PM
Last Post: onit
  Need help creating a simple script Nonameface 12 4,423 Jul-14-2020, 02:10 PM
Last Post: BitPythoner
  printing class properties from numpy.ndarrays of objects pjfarley3 2 1,909 Jun-08-2020, 05:30 AM
Last Post: pjfarley3

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020