10 Replies - 668 Views - Last Post: 10 November 2017 - 09:42 AM Rate Topic: -----

#1 Frenchi33  Icon User is offline

  • D.I.C Head

Reputation: 1
  • View blog
  • Posts: 50
  • Joined: 20-November 16

Inheritance Program

Posted 07 November 2017 - 07:34 PM

Hi guys, I'm stuck my program for school. We're studying inheritance and I'm basically done, but need help with this last section:

"Further, provide a method to advance the student from level to level. If a
student advances from level 4, that means that the student has graduated, and
the graduate indicator should be set to indicate that fact."

My first question is, how would I go about advancing the level of Undergraduates? I've just placed a "pass" on the method. Also, I don't get what the difference between the Undergraduate and Graduate classes should be. Should I just removed the set_class_level() and set_grade_point_average() methods in the Graduate class? Another thing is, I can just type that the level is "1" on the Graduate class when creating instances like this:
graduate1 = Graduate("Michael", "Scott", 1234567, "In-State", 2, 3.5)
print(graduate1)
and there's really no difference between the two methods.

You guys can see the full description in the code:

""" -*- coding: utf-8 -*-
HW21 - CSC 201 - Classes and Inheritance:
------------------------------------------------------------------------------
From the class Person developed in the handout, derive a class called Student.
An instance of Student has a student identification number and an indicator of
in-state student or out-of-state residence. Use appropriate naming conventions
for your class varibales. Write appropriate methods and include "Docstrings"
where appropriate. Write driver code to test all of your methods.

From your class Student, above, derive a class called Undergrad. An instance
of undergrad has a class number (or level) of 1, 2, 3, or 4, a grade point
average (0.0 through 4.0, inclusive), and an indicator for "graduated", in
addition to the class variables in its base class. Level 1 = freshman, level
2 = sophomore, level 3 = junior, and level 4 = senior.

Further, provide a method to advance the student from level to level. If a
student advances from level 4, that means that the student has graduated, and
the graduate indicator should be set to indicate that fact. As in the above,
write appropriate class methods and write non-class driver code to test your
methods thoroughly.

Note:

    1. A student can transfer into the school at level 1, 2, 3, or 4, but the
    student cannot transfer in as "graduated".


    2. A student who starts with the school always starts with a grade point
    average of 0.0. Grade point averages are never transferred from some other
    school. """

class Person(object): # finished
    def __init__(self, first_name = '', last_name = ''):
        """ Creates a Person given a First Name and Last Name. """
        # create instances
        self.__first_name = first_name
        self.__last_name = last_name

    def __str__(self):
        result_str = "Name: {}".\
        format(self.__last_name + ", " + self.__first_name)
        
        return result_str

    def get_first_name(self):
        return self.__first_name

    def get_last_name(self):
        return self.__last_name

    def set_first_name(self):
        return self.__first_name

    def set_last_name(self):
        return self.__last_name
# ----------------------------------------------------------------------------
class Student(Person): # finished
    """ Create a Student given a Student ID and a Residence (inherits 
    attributes from class Person). """
    def __init__(self, first_name = '', last_name = '', \
                 student_id = 0, residence = ''):

        # inherit parameter arguments from class Person
        Person.__init__(self, first_name, last_name)
        # create new instances
        self.__student_id = student_id
        self.__residence = residence

    def __str__(self):
        result_str = Person.__str__(self)

        result_str = result_str + "; Student ID: {}, Residence: {}".\
        format(self.__student_id, self.__residence)
        
        return result_str

    def get_student_id(self):
        return self.__student_id

    def set_student_id(self, new_student_id):
        self.__student_id = new_student_id

    def get_residence(self):
        return self.__residence

    def set_residence(self, new_residence):
        self.__residence = new_residence
# ----------------------------------------------------------------------------
class Undergradraduate(Student): # not finished
    """ Create an Undergrad Student given a Class Level, Grade Point Average, 
    and a Graduate indicator (inherits from class Student). """
    def __init__(self, first_name = '', last_name = '', \
                 student_id = 0, residence = '', class_level = 1, \
                 grade_point_average = 0.0):

        # inherit parameter arguments from class Student
        Student.__init__(self, first_name, last_name, student_id, residence)
        # create new instances
        self.__class_level = class_level
        self.__grade_point_average = grade_point_average
        self.__graduate = False

    def __str__(self):
        result_str = Student.__str__(self)

        result_str = result_str + ", Class Level: {}, GPA: {}, Graduate: {}".\
        format(self.__class_level, self.__grade_point_average, \
               self.__graduate)

        return result_str

    def get_class_level(self):
        return self.__class_level

    def set_class_level(self, new_class_level):
        self.__class_level = new_class_level

    def get_grade_point_average(self):
        return self.__grade_point_average

    def set_grade_point_average(self, new_grade_point_average):
        self.__grade_point_average = new_grade_point_average

    # H.E.L.P.
    def advance_level(self):
        pass
# ----------------------------------------------------------------------------
class Graduate(Student): # not finished
    """ Create a Graduate Student given a Class Level, Grade Point Average, 
    and a Graduate indicator (inherits from class Student). """
    def __init__(self, first_name = '', last_name = '', \
                 student_id = 0, residence = '', class_level = 1, \
                 grade_point_average = 0.0):

        # inherit parameter arguments from class Student
        Student.__init__(self, first_name, last_name, student_id, residence)
        # create new instances
        self.__class_level = class_level
        self.__grade_point_average = grade_point_average
        self.__graduate = True

    def __str__(self):
        result_str = Student.__str__(self)

        result_str = result_str + ", Class Level: {}, GPA: {}, Graduate: {}".\
        format(self.__class_level, self.__grade_point_average, \
               self.__graduate)

        return result_str

    def get_class_level(self):
        return self.__class_level

    def set_class_level(self, new_class_level):
        self.__class_level = new_class_level

    def get_grade_point_average(self):
        return self.__grade_point_average

    def set_grade_point_average(self, new_grade_point_average):
        self.__grade_point_average = new_grade_point_average
# ----------------------------------------------------------------------------
graduate1 = Graduate("Michael", "Scott", 1234567, "In-State", 2, 3.5)
print(graduate1)



As you can see, the class level is "2", which means a Sophomore, but it's in the Graduate() class, which doesn't make sense. It's not necessary to somehow restrict certain numbers to be passed as arguments is there? But more importantly, I'm not sure how to advance the levels in the Undergraduate class... Any tips?

This post has been edited by Frenchi33: 07 November 2017 - 07:46 PM


Is This A Good Question/Topic? 0
  • +

Replies To: Inheritance Program

#2 DK3250  Icon User is offline

  • Pythonian
  • member icon

Reputation: 320
  • View blog
  • Posts: 1,055
  • Joined: 27-December 13

Re: Inheritance Program

Posted 08 November 2017 - 02:13 PM

Can it be as simple as this (line 125):
def advance_level(self):
    self.__class_level += 1
    if  self.__class_level > 4:
        self.__graduate = True


I think I would merge the two classes: Undergraduate() (misspelled in line 89) and Graduate(). To my understanding the data are similar for the two groups; you can distinguish between them by testing whether self.__graduate is True or False.

The two set methods in line 51 and 54 are missing the parameter to set - they are just copies of the get-methods. On the other hand such get- and set- methods are (to my best understanding) quite un-Pythonic and should be omitted. All you need is a decent __init__() method.

This post has been edited by DK3250: 08 November 2017 - 02:14 PM

Was This Post Helpful? 0
  • +
  • -

#3 Frenchi33  Icon User is offline

  • D.I.C Head

Reputation: 1
  • View blog
  • Posts: 50
  • Joined: 20-November 16

Re: Inheritance Program

Posted 08 November 2017 - 03:38 PM

Yeah, I realized the set and get methods were the same, so I corrected them. The reason we're using them is because we're about to transition into Java and I think that's something that's more prevalent in Java.

Also, I realized the Graduate class is unnecessary, so here's my updated code:

class Person(object): # finished
    def __init__(self, first_name = '', last_name = ''):
        """ Creates a Person given a First Name and Last Name. """
        # create instances
        self.__first_name = first_name
        self.__last_name = last_name

    def __str__(self):
        result_str = "Name: {}".\
        format(self.__last_name + ", " + self.__first_name)
        
        return result_str

    # getters
    def get_first_name(self):
        return self.__first_name

    def get_last_name(self):
        return self.__last_name

    # setters
    def set_first_name(self, new_first_name):
        self.__first_name = new_first_name

    def set_last_name(self, new_last_name):
        self.__last_name = new_last_name
# ----------------------------------------------------------------------------
class Student(Person): # finished
    """ Create a Student given a Student ID and a Residence (inherits 
    attributes from class Person). """
    def __init__(self, first_name = '', last_name = '', \
                 student_id = 0, residence = ''):

        # inherit parameter arguments from class Person
        Person.__init__(self, first_name, last_name)
        # create new instances
        self.__student_id = student_id
        self.__residence = residence

    def __str__(self):
        result_str = Person.__str__(self)

        result_str = result_str + "; Student ID: {}; Residence: {}".\
        format(self.__student_id, self.__residence)
        
        return result_str

    # getters
    def get_student_id(self):
        return self.__student_id

    def get_residence(self):
        return self.__residence

    # setters
    def set_student_id(self, new_student_id):
        self.__student_id = new_student_id

    def set_residence(self, new_residence):
        self.__residence = new_residence
# ----------------------------------------------------------------------------
class Undergraduate(Student): # not finished
    """ Create an Undergrad Student given a Class Level, Grade Point Average, 
    and a Graduate indicator (inherits from class Student). """
    def __init__(self, first_name = '', last_name = '', student_id = 0, \
                 residence = '', class_level = 1, grade_point_average = 0.0):

        # inherit parameter arguments from class Student
        Student.__init__(self, first_name, last_name, student_id, residence)
        # create new instances
        self.__class_level = class_level
        self.__grade_point_average = grade_point_average
        self.__graduate = 'No'

    def __str__(self):
        result_str = Student.__str__(self)

        result_str = result_str + "; Class Level: {}; GPA: {}; Graduate: {}".\
        format(self.__class_level, self.__grade_point_average, self.__graduate)

        return result_str

    # getters
    def get_class_level(self):
        return self.__class_level

    def get_grade_point_average(self):
        return self.__grade_point_average

    # setters
    def set_class_level(self, new_class_level):
        self.__class_level = new_class_level

    def set_grade_point_average(self, new_grade_point_average):
        self.__grade_point_average = new_grade_point_average

    # advance_student from level to level
    def advance_student(self):
        pass



I'll take a look at what wrote about the advance_student() method. Thanks for your help DK.
Was This Post Helpful? 0
  • +
  • -

#4 Frenchi33  Icon User is offline

  • D.I.C Head

Reputation: 1
  • View blog
  • Posts: 50
  • Joined: 20-November 16

Re: Inheritance Program

Posted 08 November 2017 - 04:29 PM

Here is my full finished program along with tests if anyone cares to look at it:
And to DK, the set and get methods are just something my teacher wants in this assignment. If it's not Pythonic, I'm sorry, but I can't change that. Although, if you'd care to teach me a better way of doing this for the future, I'm all ears.

""" -*- coding: utf-8 -*-
HW21 - CSC 201 - Classes and Inheritance:
------------------------------------------------------------------------------
From the class Person developed in the handout, derive a class called Student.
An instance of Student has a student identification number and an indicator of
in-state student or out-of-state residence. Use appropriate naming conventions
for your class varibales. Write appropriate methods and include "Docstrings"
where appropriate. Write driver code to test all of your methods.

From your class Student, above, derive a class called Undergrad. An instance
of undergrad has a class number (or level) of 1, 2, 3, or 4, a grade point
average (0.0 through 4.0, inclusive), and an indicator for "graduated", in
addition to the class variables in its base class. Level 1 = freshman, level
2 = sophomore, level 3 = junior, and level 4 = senior.

Further, provide a method to advance the student from level to level. If a
student advances from level 4, that means that the student has graduated, and
the graduate indicator should be set to indicate that fact. As in the above,
write appropriate class methods and write non-class driver code to test your
methods thoroughly.

Note:

    1. A student can transfer into the school at level 1, 2, 3, or 4, but the
    student cannot transfer in as "graduated".


    2. A student who starts with the school always starts with a grade point
    average of 0.0. Grade point averages are never transferred from some other
    school. """

class Person(object):
    def __init__(self, first_name = '', last_name = ''):
        """ Creates a Person given a First Name and Last Name. """
        # create instances
        self.__first_name = first_name
        self.__last_name = last_name

    def __str__(self):
        result_str = "Name: {}".\
        format(self.__last_name + ", " + self.__first_name)
        
        return result_str

    # getters
    def get_first_name(self):
        return self.__first_name

    def get_last_name(self):
        return self.__last_name

    # setters
    def set_first_name(self, new_first_name):
        self.__first_name = new_first_name

    def set_last_name(self, new_last_name):
        self.__last_name = new_last_name
# ----------------------------------------------------------------------------
class Student(Person):
    """ Create a Student given a Student ID and a Residence (inherits 
    attributes from class Person). """
    def __init__(self, first_name = '', last_name = '', \
                 student_id = 0, residence = ''):

        # inherited from class Person
        Person.__init__(self, first_name, last_name)
        # create new class instances
        self.__student_id = student_id
        self.__residence = residence

    def __str__(self):
        result_str = Person.__str__(self)

        result_str = result_str + "; Student ID: {}; Residence: {}".\
        format(self.__student_id, self.__residence)
        
        return result_str

    # getters
    def get_student_id(self):
        return self.__student_id

    def get_residence(self):
        return self.__residence

    # setters
    def set_student_id(self, new_student_id):
        self.__student_id = new_student_id

    def set_residence(self, new_residence):
        self.__residence = new_residence
# ----------------------------------------------------------------------------
class Undergraduate(Student):
    """ Create an Undergrad Student given a Class Level, Grade Point Average, 
    and a Graduate indicator (inherits from class Student). """
    def __init__(self, first_name = '', last_name = '', student_id = 0, \
                 residence = '', class_level = 1, grade_point_average = 0.0):

        # inherited from class Student
        Student.__init__(self, first_name, last_name, student_id, residence)
        # create new class instances
        self.__class_level = class_level
        self.__grade_point_average = grade_point_average
        self.__graduate_status = False

    def __str__(self):
        result_str = Student.__str__(self)

        result_str = result_str + "; Class Level: {}; GPA: {}; Graduate: {}".\
        format(self.__class_level, self.__grade_point_average, \
               self.__graduate_status)

        return result_str

    # getters
    def get_class_level(self):
        return self.__class_level

    def get_grade_point_average(self):
        return self.__grade_point_average

    def get_graduate_status(self):
        return self.__graduate_status

    # setters
    def set_class_level(self, new_class_level):
        self.__class_level = new_class_level

    def set_grade_point_average(self, new_grade_point_average):
        self.__grade_point_average = new_grade_point_average

    # advance_student from level to level
    def advance_student(self):
        """ Advances a Student's class level (changes graduation \
        status if level > 4). """
        self.__class_level += 1
        if self.__class_level > 4:
            self.__graduate_status = True
# ----------------------------------------------------------------------------
#                                   M.A.I.N.
# ----------------------------------------------------------------------------
print()
print("Testing class Person -----------------> ", end = '')
p1 = Person("Will", "Smith")

# __init__() and __str__() test
assert(p1.__str__() == "Name: Smith, Will")

# getters test
assert(p1.get_first_name() == "Will")
assert(p1.get_last_name() == "Smith")

# setters test
p1.set_first_name("Michael")
assert(p1.get_first_name() == "Michael")

p1.set_last_name("Scott")
assert(p1.get_last_name() == "Scott")

print("All tests have passed.")
print()
# ----------------------------------------------------------------------------
print("Testing class Student ----------------> ", end = '')
s1 = Student("Britney", "Spears", 1234567, "Out-of-State")

# __init__() and __str__() test
assert(s1.__str__() == "Name: Spears, Britney; Student ID: 1234567; " + \
       "Residence: Out-of-State")

# getters test
assert(s1.get_first_name() == "Britney")
assert(s1.get_last_name() == "Spears")

assert(s1.get_student_id() == 1234567)
assert(s1.get_residence() == "Out-of-State")

# setters test
s1.set_first_name("Daenerys")
assert(s1.get_first_name() == "Daenerys")

s1.set_last_name("Targaryen")
assert(s1.get_last_name() == "Targaryen")

s1.set_student_id("9876543")
assert(s1.get_student_id() == "9876543")

s1.set_residence("In-State")
assert(s1.get_residence() == "In-State")

print("All tests have passed.")
print()
# ----------------------------------------------------------------------------
print("Testing class Undergraduate ----------> ", end = '')
u1 = Undergraduate("Buzz", "Lightyear", 9999999, "In-State", 2, 3.2)

# __init__() and __str__() test
assert(u1.__str__() == "Name: Lightyear, Buzz; Student ID: 9999999; " + \
       "Residence: In-State; Class Level: 2; GPA: 3.2; Graduate: False")

# getters test
assert(u1.get_first_name() == "Buzz")
assert(u1.get_last_name() == "Lightyear")
assert(u1.get_student_id() == 9999999)
assert(u1.get_residence() == "In-State")
assert(u1.get_class_level() == 2)
assert(u1.get_grade_point_average() == 3.2)

# setters test
u1.set_first_name("Tiger")
assert(u1.get_first_name() == "Tiger")

u1.set_last_name("Woods")
assert(u1.get_last_name() == "Woods")

u1.set_student_id("1324354")
assert(u1.get_student_id() == "1324354")

u1.set_residence("Out-of-State")
assert(u1.get_residence() == "Out-of-State")

u1.set_class_level(4)
assert(u1.get_class_level() == 4)

u1.set_grade_point_average(3.9)
assert(u1.get_grade_point_average() == 3.9)

# advance_student() test
u1 = Undergraduate("Roronoa", "Zoro", 6918755, "In-State", 1, 2.9)
assert(u1.get_class_level() == 1)
assert(u1.get_graduate_status() == False)

u1.advance_student()
assert(u1.get_class_level() == 2)
assert(u1.get_graduate_status() == False)

u1.advance_student()
assert(u1.get_class_level() == 3)
assert(u1.get_graduate_status() == False)

u1.advance_student()
assert(u1.get_class_level() == 4)
assert(u1.get_graduate_status() == False)

u1.advance_student()
assert(u1.get_class_level() == 5)
assert(u1.get_graduate_status() == True)

print("All tests have passed.")


Was This Post Helpful? 0
  • +
  • -

#5 Frenchi33  Icon User is offline

  • D.I.C Head

Reputation: 1
  • View blog
  • Posts: 50
  • Joined: 20-November 16

Re: Inheritance Program

Posted 08 November 2017 - 06:20 PM

Also, what would be considered the "output" of this program? It basically creates people objects with attributes, but it's not like we have to print them out. It seems more like a data storage type of thing. I'm confused on what would be considered "output."
Was This Post Helpful? 0
  • +
  • -

#6 DK3250  Icon User is offline

  • Pythonian
  • member icon

Reputation: 320
  • View blog
  • Posts: 1,055
  • Joined: 27-December 13

Re: Inheritance Program

Posted 09 November 2017 - 12:05 AM

You are right, the program is more of a 'bookkeeping' than output generating.
However, all the get-methods can be regarded as output. Output needs not be a print statement or graphics; if the 'user' is another program (maybe hosting the HMI), then data output, like the result of the get-methods, is just fine...
Was This Post Helpful? 0
  • +
  • -

#7 DK3250  Icon User is offline

  • Pythonian
  • member icon

Reputation: 320
  • View blog
  • Posts: 1,055
  • Joined: 27-December 13

Re: Inheritance Program

Posted 09 November 2017 - 12:37 PM

Let me come back to why getters and setters are non-pythonic.
In other languages such functions are used to get and set private attributes of an object.
In Python a private object does not exist.
Even if you use a double underscore preset, the attribute is not really private, it is just slightly more complicated to access.

As an example, look to your code in post #4, line 68:
self.__student_id = student_id

You attempt to make self.__student_id a private attribute.
Let's see if it is really private; we add as last line of code:
print(s1.__student_id)
And, sure enough, we get an error:
Traceback (most recent call last):
  File "C:\Python34\test.py", line 250, in <module>
    print(s1.__student_id)
AttributeError: 'Student' object has no attribute '__student_id'
It appears as if the attribute is private.
But in reality the double underscore only mingles a bit with the attribute name; let's try this
print(s1._Student__student_id)
Whau, now the 'private' attribute is not so private any more...!

My conclusion: As an attribute can never be private in Python, better drop the double underscore if the attribute is managed form outside the object scope.
Oh, - and the point: Then the need for getters and setters disappear; the attributes can be managed directly.

This post has been edited by DK3250: 09 November 2017 - 12:44 PM

Was This Post Helpful? 0
  • +
  • -

#8 andrewsw  Icon User is online

  • the case is sol-ved
  • member icon

Reputation: 6379
  • View blog
  • Posts: 25,770
  • Joined: 12-December 12

Re: Inheritance Program

Posted 09 November 2017 - 12:48 PM

The name mangling with a double underscore is a statement that this attribute is private, and that we trust other programmers to treat it as such.
Was This Post Helpful? 0
  • +
  • -

#9 DK3250  Icon User is offline

  • Pythonian
  • member icon

Reputation: 320
  • View blog
  • Posts: 1,055
  • Joined: 27-December 13

Re: Inheritance Program

Posted 09 November 2017 - 12:55 PM

Sure andrewsw, but doesn't a single leading underscore send the same signal without the need for getters and setters?
I'm a little outside my comfort zone here, so please bear with me...
Was This Post Helpful? 0
  • +
  • -

#10 andrewsw  Icon User is online

  • the case is sol-ved
  • member icon

Reputation: 6379
  • View blog
  • Posts: 25,770
  • Joined: 12-December 12

Re: Inheritance Program

Posted 09 November 2017 - 01:07 PM

Yes, I was about to edit my post to say "or even just a single underscore".

Here's a link.

The double underscore invokes name mangling but, because both are exercising trust, I suspect that many are happy to use a single underscore.

I don't work with Python regularly myself, but I suspect the double underscore is saying "I trust you, but I still want to emphasise that this should be private" and make it a less obvious reference.

Quote

A single leading underscore is simply a convention that means, "You probably shouldn't use this." It doesn't do anything to stop someone from using the attribute.

A double leading underscore actually changes the name of the attribute so that two classes in an inheritance hierarchy can use the same attribute name, and they will not collide.

Was This Post Helpful? 0
  • +
  • -

#11 Frenchi33  Icon User is offline

  • D.I.C Head

Reputation: 1
  • View blog
  • Posts: 50
  • Joined: 20-November 16

Re: Inheritance Program

Posted 10 November 2017 - 09:42 AM

Thanks DK and Andrew!
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1