CIT228 - Advanced Database Systems

 Python Classes, Objects and Inheritance


I. Overview

Chapter 9 covers object oriented programming in Python. You will be working with classes, objects and inheritance.

To see an explanation of all lecture material in chapter 9, watch: https://youtu.be/V2fGg8bxDdw

To see sample exercises that go with the Try It Yourself sections in the chapter, download: chapter_09.zip


II. OOP Terminology Review

Python is an object oriented programming language. 

Terminology used in Python includes:

Class - blueprint for creating objects where you define what data is stored and what actions can affect the data.  A class is conceptual (it isn't anything you can manipulate with code until you instantiate it).   

A class definition can be compared to a cake recipe. Where the recipe is the class and the cake is an instance of the class.  Recipes require ingredients and instructions.  Classes require variables and methods. You must use the ingredients and instructions to create the cake just like you must create a class object to store data in the variables and  use the methods.

Instantiation - when you create an object using a class, you instantiate the object  (you are creating something with the class blueprint).

Object - - one instance of the class.  Once you create an object from a class, the object has an identity (a unique address), a state (the data that it stores), and behavior (the methods that it contains). As a program runs, an object’s state may change.

Attribute - data variable that is part of a class (other languages may refer to it as a member or data member)

Method - a function that is part of a class and must be invoked (or called) by a class object. Methods are used to create, modify or delete class objects.  Some methods are built into the language and some are created by the developer.

Polymorphism -  Python includes method overriding and it handles method overloading by using parameters with default values which makes them optional

Encapsulation - hides the details of the class from the outside world.  You create class objects and call class methods, but you don't know the internals of how the class works. You don't know what attributes are created and you don't know how the different methods are coded.

Abstraction - achieved through encapsulation.  It is the process of hiding the real implementation of an application from the user and emphasizing how to use the application

Inheritance - you pull in an existing class as a base so you have access to all its attributes and methods and then you add more attributes and methods to it. 

 


III. Creating & Using Classes

Classes contain attributes and methods.  Classes are typically created in external files and imported into your program.

A.  Creating a class

To create a class,  you need to use the keyword class followed by the name of the class you are creating and a colon.

Syntax:   class  ClassName:

Example:  class Hobby:

By convention, class names are capitalized.  If the class name consists of more than one word, you can use camel casing or you can use underscores _ between words.

Below the class name, you would include attributes and methods. 

B.  Creating Class Methods

Coding and calling methods works similarly to coding and calling a function.  The primary difference is methods require class objects and functions do not.

One method that is automatically called when you create an object is the constructor.   

In Python, the constructor is named __init__()    It has two underscores before init and two underscores after init.  Constructors are used to set attributes to starting values  (it initializes them).

In ALL methods, the first parameter is self. 

NOTE:  Python doesn't use get and set methods the same way other languages use them  (other languages use them to encapsulate data).  In Python, getters and setters are used to:  1)  add validation logic required for getting or setting a value and 2)  avoid direct access to a private variable

Syntax:   

def __init__(self, attribute1, attribute2,  attributeN):
         self.attribute1 = attribute1
         self.attribute2 = attribute2
         self.attribute3 = attribute3

Example:

def __init__(self, name, description, specialty):
         self.name = name
         self.description = description
         self.specialty = specialty

def printSpecialty(self):
         print(f"You specialize in {self.specialty} {self.name}")

If you want to set a default value in the __init__ constructor, you simply omit the attribute in the parameter list and assign the default value

Example:

class Trip:

    def __init__(self, location, destination, totalMiles):
        self.location = location
        self.destination = destination
        self.totalMiles = int(totalMiles)
        self.milesTraveled = 0

 

C.  Creating and Using Class Objects

To create an object, you set the object variable equal to the name of the class and a set of parentheses. Inside the parentheses, you code the parameters for the constructor separated by commas.

Syntax:   objectName = ClassName(argument1, argument2, argumentN)

or

objectName = ClassName(
      parameter1=argument1,
      parameter2=argument2,
      parameter3=argument3,
      parameter4=argument4
)

Example:

hobby1 = Hobby("Photography","Black and White and Color Photography","Landscape, Macro and Portrait")
hobby2 = Hobby(
    name="Running",
    description="Jogging and Interval Running",
    specialty="10K"
)

To access the attributes of an object, you code the name of the object followed by the dot operator (.) and the name of the attribute.

Example:

print("My first hobby is ", hobby1.name)
print("My second hobby is ", hobby2.name)

To call a method from an object, you code the name of the object followed by the dot operator (.), the name of the method, and a set of parentheses. Inside the parentheses, you code the parameters for the method separated by commas.   The object itself will automatically go to the method as "self", so you don't need to include that in the parenthesis

Example:

hobby1.printSpecialty()
hobby2.printSpecialty()

Full Programming Example:

class Hobby:

    def __init__(self, name, description, specialty):
        self.name = name
        self.description = description
        self.specialty = specialty

    def printSpecialty(self):
        print(f"You specialize in {self.specialty} {self.name}")


hobby1 = Hobby("Photography","Black and White and Color Photography","Landscape, Macro and Portrait")
hobby2 = Hobby(
    name="Running",
    description="Jogging and Interval Running",
    specialty="10K"
)

print("My first hobby is ", hobby1.name)
print("My second hobby is ", hobby2.name)

hobby1.printSpecialty()
hobby2.printSpecialty()

NOTE:  We will be learning how to modularize classes, but for now we will include them at the top of the program.

D.  Deleting objects and attributes

You can delete class objects or attributes using the del keyword

Syntax:  del objectName   or  del objectName.attribute

Example:

del hobby1

or

del hobby2.description


Hands On #1 -Practice creating and using classes

To see a video explanation, watch: https://youtu.be/HcIj41WT4CM

1. Open the CIT228 folder and create a new folder named Chapter9 

2. Create a new file and call it restaurant_class.py  (save the file into your Chapter9 folder)

3. Using the restaurant_class.py file, complete Try It Yourself 9-1 and then add the code for Try It Yourself 9-2 below the code for 9-1  (page 162)

Sample Output:

 

Exercise 9-1
=================================================================

-------------Here are your selections-------------
Restaurant= TGI Friday
Cuisine= American
TGI Friday serves American cuisine.
TGI Friday is open.

Exercise 9-2
=================================================================

Olive Garden serves Italian cuisine.
Hunan serves Chineese cuisine.
La Senorita serves Mexican cuisine.

 

4. Complete Try It Yourself 9-3 on page 162 and name the fiile user_class.py.

Sample Output:

Welcome back George!
George Jetson has a username of georgejetson,
a password of astro123 and an email address of george@jetson.net.

Welcome back Wilma!
Wilma Flintstone has a username of flinty,
a password of pebbles and an email address of wilma@flint.net.

Welcome back Betty!
Betty Rubble has a username of bets,
a password of bambam and an email address of bets@rub.com.


D.  Modifying Object Attributes

There are three ways to modify attribute values: 

1.  Modify Attributes using Objects

To modify the attribute using the object, use the objectName, a dot, and the attribute name in an assignment statement

Syntax:  objectName.attribute = new value

hobby2.name="Weight Training"
hobby2.description="Free weights and machines"
hobby2.specialty="Arms and Legs"

2.  Modify Attributes using a Method

You can call a method and pass values which will be assigned to the attribute within the method

Syntax:  objectName.methodName(self, value)

New Class and Method Example:   The newDestination method is assigning a new value to destination and totalMiles based on the data that was passed.  It is also resetting milesTraveled and printing out a message.

class Trip:

    def __init__(self, location, destination, totalMiles):
        self.location = location
        self.destination = destination
        self.totalMiles = int(totalMiles)
        self.milesTraveled = 0

    def newDestination(self,destination,totalMiles):
        self.destination = destination
        self.totalMiles =int(totalMiles)
        self.milesTraveled = 0
        print(f"Your destination has been set to {self.destination}.")
        print(f"Your total miles have been set to: {self.totalMiles}.")
        print(f"Your miles traveled have been reset to {self.milesTraveled}")

Here's the section of code where the object invokes the newDestination method:

change=input("Do you want to enter a new destination?  (y for yes)")   

if change=="y":
         dest = input("Where are you traveling to?")
         miles = input("What is the total mileage for the trip?")  
         trip.newDestination(dest,miles)

 

3.  Modify Attributes by Calculating a new value in a Method

You can change values in methods using arithmetic expressions.

Example from the book:  The odemeter reading is adjusted within a method

    def update_odometer(self, mileage):
        """
        Set the odometer reading to the given value.
        Reject the change if it attempts to roll the odometer back.
        """
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer!")

Here's the object invoking the method:

my_used_car.update_odometer(23_500)

To see the full blown program, view:  Car Example

Full Blown Trip Example:  The milesTraveled method adds the miles passed by the user to the number of miles traveled.  Because the user is entering input data in this program, numbers were automatically given the string data type.  So, all numbers had to be converted to integer to perform arithmetic on them.  In the __init__ constructor, data has been converted to int. You will also notice this in the newDestinaton method.  For updateMiles, the data is converted to int within the program before the method is called (which is another way of converting the data)

class Trip:

    def __init__(self, location, destination, totalMiles, milesTraveled=0):
        self.location = location
        self.destination = destination
        self.totalMiles = int(totalMiles)
        self.milesTraveled = int(milesTraveled)

    def newDestination(self,destination,totalMiles):
        self.destination = destination
        self.totalMiles = int(totalMiles)
        self.milesTraveled = 0
        print(f"Your destination has been set to {self.destination}.")
        print(f"Your total miles have been set to: {self.totalMiles}.")
        print(f"Your miles traveled have been reset to {self.milesTraveled}")

    def getMilesLeft(self):
        return self.totalMiles - self.milesTraveled

    def updateMilesTraveled(self,miles):
        self.milesTraveled += miles    

start = input("Where are you traveling from?")
dest = input("Where are you traveling to?")
miles = input("What is the total mileage for the trip?")
trip = Trip(start,dest,miles)
go=""
left = trip.getMilesLeft()

while left>0 and go!="q":
    change=input("Do you want to enter a new destination?  (y for yes)")   
    if change=="y":
         dest = input("Where are you traveling to?")
         miles = input("What is the total mileage for the trip?")  
         trip.newDestination(dest,miles)
    m = input("How many miles have you traveled today?")
    m=int(m)
    trip.updateMilesTraveled(m)
    print("You have ", trip.getMilesLeft(), " miles to go!")
    left = trip.getMilesLeft()
    go = input("Do you want to continue entering miles (q to quit)")

Hands On #2:  Adding attributes and methods to classes.

To see a video explanation, watch https://youtu.be/SZmbIczCMLk

1.  Open restaurant_class.py and save it as restaurant_attributes.py    Complete Try It Yourself 9-4 on page 167  using the restaurant_attributes.py file.   Feel free to modify the main program (you can remove the code from exercises 9-1 and 9-2.   Make sure you have all the required number_served changes. 

You are being asked to: 

1)  change the attribute to a different value in the main program
2)  change the number_served attribute to a different value using the set_number_served method
3)  add to the number_served using the increment_number_served method

Sample Output:

Exercise 9-4
=================================================================

Outback Steakhouse is open.
Outback Steakhouse serves American cuisine.

# processing initial number served #
The starting number of customers was: 4

# changing the number_served attribute to 200 #
The number of customers served has been changed to 200

# changing the number_served using the set_number_served method #
How many total customers have been served today?300
The number of customers served is currently 300

# addint to the number_served using the increment_number_served method #
How many additional customers have been served?45

# printing the grand total for the day #
The number of customers served this business day = 345

 

2. Complete Try it Yourself 9-5 on page 167 using the user_class.py file.

Partial output that includes new requirements from exercise 9-5

Flo Schmoe has a username of flow,
a password of eieiflo and an email address of flo@schmoe.net.
Flo has tried to login 1 times!
Flo has tried to login 2 times!
Flo has tried to login 3 times!
Flo has tried to login 4 times!
Flo has tried to login 5 times!
Flo you have exceeded the number of login attempts.
The number of attempts has been reset to: 0
Your account has been locked for 30 minutes, please try back later or call tech support for help!.


IV  Inheritance

Inheritance lets you create a new class based on an existing class. You can use the methods and attributes of the existing class and just add the new attributes and methods that you want to use.  If there is a method in the existing class that you don't like, you can override it and create your own.

The class you inherit from is called a base class or parent class (some languages also refer to it as a superclass). 

The class you are creating is called the derived class or child class (some languages also refer to it as a subclass).

NOTE:  Our book uses the terminology parent and child; however, you should be familiar with the different terms used for parent and child classes because many sites use them interchangably.

A. How to code the child class and methods

To create the child class, use the following syntax:

Syntax:  class childClass(parentClass):

Example of a Student class derived from a Person parent class:

class Person:
  def __init__(self, fname, lname):
    self.fname = fname
    self.lname = lname

  def print(self):
    print(self.fname, self.lname)

class Student(Person):

Our new child class cannot initialize parent class attributes with the __init__() constructor  - the parent class must do that!  We need to include a call to the parent class within the child class __init__() constructor and we need to pass the data the parent __init__() constructor needs.

There are 2 ways you can call the parent class, you can use the parent classname OR you can use the super() function which allows you to call any method from the parent class.  The advantange of using the super() function is the child class will inherit all the methods and properties from its parent AND you will notice in the constructor, you do not have to pass "self" along to the parent if you use super()

Syntax:

def __init__(self, parentAttr1, parentAttr2, parentAttrN, childAttr1, childAttr2, childAttrN):
        parentClass.__init__(self,parentAttr1, parentAttr2, parentAttrN)
        self.childAttr1 = childAttr1
        self.childAttr2 = childAttr2
        self.childAttrN = childAttrN

or

def __init__(self, parentAttr1, parentAttr2, parentAttrN, childAttr1, childAttr2, childAttrN):
        super().__init__(parentAttr1, parentAttr2, parentAttrN)
        self.childAttr1 = childAttr1
        self.childAttr2 = childAttr2
        self.childAttrN = childAttrN

The new attributes of the child class are initialized in the child constructor after the parent class is called.  They are initialized the same way you initialized values in the parent class.

Child class methods are also set up the same way as the parent class.   If you include a method with the same name as the parent class, Python will look at the type of object invoking (or calling) the method.  If it is a child class object, it will use the child class method.  If it is a parent class object, it will use the parent class method.

Example using super() for the constructor.  You should note the parent and child both have print classes.  In the program, when the student1 object calls the print method, it will use the child print method because a child object is invoking it.  When the person1 object calls the print method, it will use the parent class print method because of the object invoking it:

class Person:
  def __init__(self, fname, lname):
    self.fname = fname
    self.lname = lname

  def print(self):
    print(self.fname, self.lname)

class Student(Person):
  def __init__(self, fname, lname, year):
    super().__init__(fname, lname)
    self.year = year

  def print(self):
    print("Welcome", self.fname, self.lname, "to the class of", self.year)

# creating and printing a student
student1 = Student("Scooby", "Doo", 2020)
student1.print()

# creating and printing a person
person1 = Person("Shaggy","Rogers")
person1.print()

B.  How to handle lists in classes and how to create a list of objects in the main program

Everything you have learned up to this point applies to classes.  The only difference is you need class objects to use attributes and methods within the class. 

Because Python is loosely typed, you can include lists in classes or dictionaries.  Python will determine the type of item being passed to the class and select the appropriate item type.

Example:   In the code below, items that are entered by the user are appended to a list named tempItems.  Once the user is done entering the items, the sales object is created and the list of items is passed to the class constructor along with the other information the user entered.

    name = input("Enter the name of the store ")
    type = input("Enter the type of merchandise sold ")
    customers = input("Enter the number of customer transactions ")
    tempItems=[]
    item = input("Enter the types of items purchased or q to quit ")
    while item != "q":
        tempItems.append(item)
        item = input("Enter the types of items purchased or q to quit ")
    sales = Specialty(
        store_name=name,
        store_type = type,
        daily_sales = customers,
        items = tempItems
    )  

In a program where you use the same object instance to store different data, you can add the object to a list which allows you to access the data later in the program.  This is no different than adding dictionary items to a storeList using the append method 

In the code below, the sales object instance is added to storeList.append(sales).

number=input("How many stores are you entering?")
number = int(number)
counter=0
storeList=[]
while counter<number:
    print("\n\nSale Summary Information\n")
    name = input("Enter the name of the store ")
    type = input("Enter the type of merchandise sold ")
    customers = input("Enter the number of customer transactions ")
    tempItems=[]
    item = input("Enter the types of items purchased or q to quit ")
    while item != "q":
        tempItems.append(item)
        item = input("Enter the types of items purchased or q to quit ")
    sales = Specialty(
        store_name=name,
        store_type = type,
        daily_sales = customers,
        items = tempItems
    )  
    sales.describe_store()
    sales.displayitems()    
    storeList.append(sales)
    counter += 1

Outside of the loop, you can still access the class objects using the list and you can use the object in the list to call class methods.

In the example below, s represents each class object stored in the list.  You can use s to call any of the class methods.

for s in storeList:
    s.describe_store()
    s.displayitems()

Full example that includes list processing similar to your next assignment:

Specialty store is derived from Store.  A list attribute named items has been added to Specialty.  Specialty contains 2 methods:   init constructor and displayItems which is set up to handle list processing.   The main program allows the user to select how many stores they want to enter and to add input for all attributes.   Each class object is created using the sales object name.  After the information is displayed back to the user, the sales object is added to a list.  Once the user is done entering information, the list of sales objects is processed displaying the store information and the item information.

class Store:
    def __init__(self,store_name,store_type, daily_sales=0):
        self.store_name=store_name
        self.store_type=store_type
        self.daily_sales=daily_sales

    def describe_store(self):
        print(f"{self.store_name} is a  {self.store_type} shop.")    

    def open_store(self):
        print(f"{self.store_name} is open.")   

    def set_daily_sales(self,sales):
        self.daily_sales = int(sales)    

    def increment_daily_sales(self,sales):
        self.daily_sales += int(sales)    

class Specialty(Store):
    def __init__(self,store_name,store_type, daily_sales, items):
        super().__init__(store_name,store_type, daily_sales)
        self.items=items

    def displayitems(self):
        print("~The following items have been purchased today~")
        for f in self.items:
            print(f.title())       

number=input("How many stores are you entering?")
number = int(number)
counter=0
storeList=[]
while counter<number:
    print("\n\nSale Summary Information\n")
    name = input("Enter the name of the store ")
    type = input("Enter the type of merchandise sold ")
    customers = input("Enter the number of customer transactions ")
    tempItems=[]
    item = input("Enter the types of items purchased or q to quit ")
    while item != "q":
        tempItems.append(item)
        item = input("Enter the types of items purchased or q to quit ")
    sales = Specialty(
        store_name=name,
        store_type = type,
        daily_sales = customers,
        items = tempItems
    )  
    sales.describe_store()
    sales.displayitems()    
    storeList.append(sales)
    counter += 1

 
for s in storeList:
    s.describe_store()
    s.displayitems()

 

B.  Adding other class objects as attributes within your class

If your class is becoming long and too detailed, you may need to pull out some attributes to create another class. 

If you do that, you can still include the data as a class attribute by assigning it to the class you created.

Syntax:  self.attribute = className()

If you do this, accessing attributes and methods can be a little tricky.

Example: To simplify the Trip class, I removed the mile information from the class and put it into a separate Miles class.  Within the trip class, I added an object instance from Miles named mileInfo and I passed it totalMiles  (this was all done in the __init__() constructor)

 self.mileInfo = Miles(totalMiles)

class Miles:
    def __init__(self,totalMiles=0,milesTraveled=0):
        self.totalMiles=int(totalMiles)
        self.milesTraveled=0
        self.milesLeft=int(totalMiles)

    def updateMilesTraveled(self,miles):
        self.milesTraveled+=miles 
        self.milesLeft-=miles         

class Trip:

    def __init__(self, location, destination,totalMiles):
        self.location = location
        self.destination = destination
        self.mileInfo = Miles(totalMiles)

    def newDestination(self,destination,totalMiles):
        self.destination = destination
        self.mileInfo = Miles(self,totalMiles)
        print(f"Your destination has been set to {self.destination}.")
        print(f"Your total miles have been set to: {self.mileInfo.totalMiles}.")
        print(f"Your miles traveled have been reset to {self.mileInfo.milesTraveled}")

So far, everything seems pretty straightforward.  However, if you want to access attributes or methods in Miles, you must do it through the mileInfo attribute that was created. 

To update the miles traveled you need to do something like this:

    m = input("How many miles have you traveled today?")
    m=int(m)
    trip.mileInfo.updateMilesTraveled(m)

trip is the object created
mileInfo is the instance of the Miles class that is an attribute in the trip class
updateMilesTraveled is a method in the Miles class

To print miles left, you need to do something like this:

    print("You have ", trip.mileInfo.milesLeft, " miles to go!")

trip is the object created
mileInfo is the instance of the Miles class that is an attribute in the trip class
milesLeft is an attribute in the Miles class

Here's the fully revised program:

class Miles:
    def __init__(self,totalMiles=0,milesTraveled=0):
        self.totalMiles=int(totalMiles)
        self.milesTraveled=0
        self.milesLeft=int(totalMiles)

    def updateMilesTraveled(self,miles):
        self.milesTraveled+=miles 
        self.milesLeft-=miles         

class Trip:

    def __init__(self, location, destination,totalMiles):
        self.location = location
        self.destination = destination
        self.mileInfo = Miles(totalMiles)

    def newDestination(self,destination,totalMiles):
        self.destination = destination
        self.mileInfo = Miles(self,totalMiles)
        print(f"Your destination has been set to {self.destination}.")
        print(f"Your total miles have been set to: {self.mileInfo.totalMiles}.")
        print(f"Your miles traveled have been reset to {self.mileInfo.milesTraveled}")
        
     
start = input("Where are you traveling from?")
dest = input("Where are you traveling to?")
miles = input("What is the total mileage for the trip?")
trip = Trip(start,dest,miles)
go=""
while go!="q":
    change=input("Do you want to enter a new destination?  (y for yes)")   
    if change=="y":
         dest = input("Where are you traveling to?")
         miles = input("What is the total mileage for the trip?")  
         trip.newDestination(dest,miles)
    m = input("How many miles have you traveled today?")
    m=int(m)
    trip.mileInfo.updateMilesTraveled(m)
    print("You have ", trip.mileInfo.milesLeft, " miles to go!")
    go = input("Do you want to continue entering miles (q to quit)")

NOTE:  The book has a similar example showing a car and battery class.


Hands On #3 - Inheritance

To see a video explanation, watch: https://youtu.be/TD15vCQMjis

1.  Open restaurant_attributes.py  and save it as restaurant_inheritance.py     Complete Try It Yourself 9-6 on page 173   Feel free to remove code from the main program that pertains to exercise 9-4 (keep the Restaurant class intact).     NOTE:  The directions are asking you to add the flavors attribute as a list.   The Store parent and Specialty child class example in the section above is similar to what you need to do.

2.  Open user_class.py and name it user_inheritance.py.   Complete Try It Yourself 9-7 and 9-8 on page 173 using the user_inheritance.py file  Make any changes needed to the main program to accomplish the required tasks.  You will have 3 classes:  User,  Admin derived from User and Privileges.   Admin is connected to User because it is derived from user (it is a child of User) and it is connected to privileges because it includes a privilege object as an attribute

Here's how I set up Admin

class Admin(User):
    def __init__(self,first_name,last_name,username,email,password,permissions):
        super().__init__(first_name,last_name,username,email,password)
        self.privileges=Privileges(permissions)

To see an example similar to what you need to do, view: Magical Creatures


V. Importing Classes

A.  Overview

So far, we have created classes at the top of the programs that use them.  In the real-world, classes are stored in separate files (modules) and they are imported into programs.  This is very similar to what we did with functions.

We will cover how to create the class module and different ways to import the classes.

B.  Creating the class module

The class file should have a docstring at the top that states the purpose of the class.  A docstring is a special comment the interpretter ignores.  it begins with 3 double quotes and it ends with 3 double quotes.  It can be on one line or multiple lines.

docstring Syntax: """   documentation text   """

Example showing the Miles and Trip classes in their own file named TripMiles.py:

""" Miles class that stores total miles, miles traveled and miles remaining """
class Miles:
    def __init__(self,totalMiles=0,milesTraveled=0):
        self.totalMiles=int(totalMiles)
        self.milesTraveled=0
        self.milesLeft=int(totalMiles)

    def updateMilesTraveled(self,miles):
        self.milesTraveled+=miles 
        self.milesLeft-=miles         

""" Trip class that stores current location, destination and mileage information """
class Trip:

    def __init__(self, location, destination,totalMiles):
        self.location = location
        self.destination = destination
        self.mileInfo = Miles(totalMiles)

    def newDestination(self,destination,totalMiles):
        self.destination = destination
        self.mileInfo = Miles(self,totalMiles)
        print(f"Your destination has been set to {self.destination}.")
        print(f"Your total miles have been set to: {self.mileInfo.totalMiles}.")
        print(f"Your miles traveled have been reset to {self.mileInfo.milesTraveled}")

 

B.  Importing a class from a module

You can import a single class or multiple classes from a module.   You can import them into a program OR into a module containing a class.

Syntax:  from fileName import className1, className2, classNameN

This technique doesn't require any additional coding or prefixing of class methods.  It is the technique used most often by developers.

Example importing the Trip and Miles class from the TripMiles module into a program

from TripMiles import Trip, Miles     
     
start = input("Where are you traveling from?")
dest = input("Where are you traveling to?")
miles = input("What is the total mileage for the trip?")
trip = Trip(start,dest,miles)
go=""
while go!="q":
    change=input("Do you want to enter a new destination?  (y for yes)")   
    if change=="y":
         dest = input("Where are you traveling to?")
         miles = input("What is the total mileage for the trip?")  
         trip.newDestination(dest,miles)
    m = input("How many miles have you traveled today?")
    m=int(m)
    trip.mileInfo.updateMilesTraveled(m)
    print("You have ", trip.mileInfo.milesLeft, " miles to go!")
    go = input("Do you want to continue entering miles (q to quit)")

Example illustrating importing into a class module and importing parent and child class modules into a program:

store.py which contains the Store parent class

class Store:
    def __init__(self,store_name,store_type, daily_sales=0):
        self.store_name=store_name
        self.store_type=store_type
        self.daily_sales=daily_sales

    def describe_store(self):
        print(f"{self.store_name} is a  {self.store_type} shop.")    

    def open_store(self):
        print(f"{self.store_name} is open.")   

    def set_daily_sales(self,sales):
        self.daily_sales = int(sales)    

    def increment_daily_sales(self,sales):
        self.daily_sales += int(sales)  

specialty.py which contains the Specialty child class and imports the Store parent class

from store import Store

class Specialty(Store):
    def __init__(self,store_name,store_type, daily_sales, items):
        super().__init__(store_name,store_type, daily_sales)
        self.items=items

    def displayitems(self):
        print("~The following items have been purchased today~")
        for f in self.items:
            print(f.title())   

myStore.py program which imports the Store class from the store module and the Specialty class from the specialty module

from store import Store
from specialty import Specialty

number=input("How many stores are you entering?")
number = int(number)
counter=0
storeList=[]
while counter<number:
    print("\n\nSale Summary Information\n")
    name = input("Enter the name of the store ")
    type = input("Enter the type of merchandise sold ")
    customers = input("Enter the number of customer transactions ")
    tempItems=[]
    item = input("Enter the types of items purchased or q to quit ")
    while item != "q":
        tempItems.append(item)
        item = input("Enter the types of items purchased or q to quit ")
    sales = Specialty(
        store_name=name,
        store_type = type,
        daily_sales = customers,
        items = tempItems
    )  
    sales.describe_store()
    sales.displayitems()    
    storeList.append(sales)
    counter += 1
for s in storeList:
    s.describe_store()
    s.displayitems()

 

C.  Other methods of importing classes

1.  Importing the module, but not the class

If you import the module and not the class with the module, when you create class objects, you will need to prefix the className with the moduleName (method class won't be impacted)

Syntax:  import moduleName

Example:  In the code below, the only thing that had to be modified was the statement creating the trip object.  instead of trip = Trip(start,dest,miles), I had to use trip=TripMiles.Trip(start,dest,miles)  Everything else remained the same

#from TripMiles import Trip, Miles 
import TripMiles    
     
start = input("Where are you traveling from?")
dest = input("Where are you traveling to?")
miles = input("What is the total mileage for the trip?")
#trip = Trip(start,dest,miles)
trip = TripMiles.Trip(start,dest,miles)
go=""
while go!="q":
    change=input("Do you want to enter a new destination?  (y for yes)")   
    if change=="y":
         dest = input("Where are you traveling to?")
         miles = input("What is the total mileage for the trip?")  
         trip.newDestination(dest,miles)
    m = input("How many miles have you traveled today?")
    m=int(m)
    trip.mileInfo.updateMilesTraveled(m)
    print("You have ", trip.mileInfo.milesLeft, " miles to go!")
    go = input("Do you want to continue entering miles (q to quit)")

2.  Importing everything

This may seem like the easy way out; however it is BAD practice because you don't know everything that may be in the module. Remember, these import techniques not only work for your own classes, but Python classes too.   You could end up with naming conflicts and other issues if you do this. 

This is not something we are going to do, but I wanted you to be aware of it in case you run into it online or at work.

Example:

from TripMiles import *

3.  Creating an alias

If you are importing a module (and not the class),  and you have a very long module name, you can give it an alias that you can use in your code. 

Syntax:  import moduleName as alias

Partial Example:   This is similar to importing the module, the only line of code impacted is the one involved in creating the object. The classname will need to be prefixed with the alias.  You'll notice that trip = TrMi.Trip(start,dest,miles)  instead of trip=Trip(start,dest,miles)

#from TripMiles import Trip, Miles 
#import TripMiles
import TripMiles as TrMi   
     
start = input("Where are you traveling from?")
dest = input("Where are you traveling to?")
miles = input("What is the total mileage for the trip?")
#trip = Trip(start,dest,miles)
#trip = TripMiles.Trip(start,dest,miles)
trip = TrMi.Trip(start,dest,miles)

 


Hands On #4 - Creating and Importing Class Modules

To see a video demonstration of part 2 and explanation of parts 1 and 3, watch:  https://youtu.be/VMpfu7Ft9OI

Part 1:  Modularizing the restaurant_inheritance.py

1.  Create 3 new files named: restaurant.py, icecream.py and myRestaurant.py

2.  Open restaurant_inheritance.py. 

a) Copy the Restaurant class and paste it into restaurant.py.   

b) Copy the IceCreamStand class and paste it into icecream.py

c)  Copy everything else  below the two classes and paste the code into myRestaurant.py

3.  Save all your changes and make the following adjustments:

a)  At the top of icecream.py, add the following import statement to import the parent Restaurant class

from restaurant import Restaurant

b)  At the top of the myRestaurant.py program, add the following import statements to bring in the Restaurant and Specialty classes

from restaurant import Restaurant
from icecream import IceCreamStand

4.  Save all your changes and run the myRestaurant.py program  (everything should work without having to modify the code)

Part 2: Modularizing user_inheritance.py

1.  Create 4 new files named: user.py, admin.py, privileges.py and myUsers.py

2.  Open user_inheritance.py

a)  Copy the User class and paste it into user.py

b)  Copy the Privileges class and paste it into privileges.py

c)  Copy the Admin class and paste it into admin.py.  Add 2 statements at the top to import the User class and the Privileges class (this is similar to what you did in icecream.py)

d)  Copy all the code below the classes and paste it into myUsers.py.  Add 3 statements at the top to import the User class, Privileges class and Admin class (this is similar to what you did in myRestaurant.py)

3.  Save all your changes and run myUsers.py - you shouldn't have to make any adjustments to the code.

Part 3:  Extra Credit (10 points)

The chapter introduces 2 new functions in the random library:  randint() and choice()

randint() randomly retrieves integers within the range you give it.

Example:

from random import randint

dice = randint(1,6)
print(dice)

choice() randomly retrieves an item from a list or tuple

Example:

from random import choice

from random import choice

print("Low card goes first")
cards=["A","1","2","3","4","5","6","7","8","9","10","J","Q","K"]
player1=choice(cards)
player2=choice(cards)
print("player1 drew a ", player1)
print("player2 drew a ", player2)
if player1<player2:
    print("player 1 goes first")
else:
    print("player 2 goes first")  

1.  Complete one of the following:


Hands On #5 - Uploading to GitHub

1.  You should have the following files in your Chapter9 folder:

Exercise Assignment Files Points
Hands On 1:  Try It Yourself 9-1 and 9-2 restaurant_class.py 3 points
Hands On 1:  Try It Yourself 9-3 user_class.py 3 points
Hands On 2: Try It Yourself 9-4 restaurant_attribute.py 3 points
Hands On 2:  Try It Yourself 9-5 user_class.py 3 points
Hands On 3: Try It Yourself 9-6 restaurant_inheritance.py  5 points
Hands On 3:  Try It Yourself 9-7 user_inheritance.py 6 points
Hands On #4 Part 1 restaurant.py, icecream.py, myRestaurant.py 3 points
Hands On #4 Part 2 user.py, admin.py, privileges.py, myUser.py 4 points
Hands On #4  Part 3 (Optional) extra credit exercise 10 points

 

2.  Upload Chapter9 to GitHub

a.  Click the ... next to CIT228 Git and select the Changes menu, Stage all Changes command.

b.  In the Message window below Source Control, enter Chapter9 and then click the ... next to CIT228 Git and select the Commit menu,  Commit Staged command

c.  Display the menu next to the CIT228 Git folder by selecting ...  and select the Push command

d.  This will put all files and folders inside your CIT228/Chapter9 directory into your GitHub repository

3.  Open a web browser and go to your CIT228 repository.  Make sure the Chapter9 directory and files are there, then copy the URL and paste it into the lab assignment dropbox (you are done with the second part of your lab assignment!)