Hey there. So without seeing the textbook chapter/assignment I’m not entirely sure what’s going on. Is the add_auto()
function part of the Automobile class? or is it an inventory/global function here? On first glance, I think some of the issues here may be due to problems with ‘scope.’ For instance, the variable count
is likely a global variable by the looks of it, however in your code it’s going to be initialized as a new variable in the function add_auto()
(which I’m assuming is a function in the Automobile
class), so every time that function is called it will be reinitialized. On the flip side, if add_auto()
is a global function (not a function in the Automobile
class) you’re calling variables scoped to an Automobile
object as global variables.
Here is how I would personally think about this. Remember, classes are like blueprints for building objects. That means that after building the blueprint you have to instantiate instances of these blueprints as objects before they can be used.
You have a class Automobile
with a bunch of attributes specific to a car on initialization. You also have an inventory that houses information derived from each instance of Automobile
. Where does a function that adds information to this inventory belong? In the Automobile
class, or as part of the inventory makeup? To word this differently: Does a car add itself to an inventory or does someone add the car to an inventory? I tend to think the latter. It doesn’t make much sense for the Automobile
class to have a function that adds its info to an inventory, rather the inventory should have a function that adds a car’s info as an entry in itself.
So let’s keep these worlds separate. Build an Automobile
blueprint (class) that allows you to create a new car object with the attributes make, model, color, year, & mileage. Then make an inventory blueprint (class) that houses the inventory data, count, as well as has methods for adding a new car, removing a car, modifying an entry, and so forth. Once that’s done you can create an instance of an inventory, and some instances of an automobile – then update the inventory object with the information from the car objects.
class Automobile:
def __init__(self):
""" Initialize a new Automobile object """
self.make = ''
self.model = ''
self.color = ''
self.year = 0
self.mileage = 0
self.auto_attributes() # This function fills in the above attributes
def auto_attributes(self):
""" Function to be called upon instantiation to set the automobiles
attributes via an input prompt. """
try:
self.make = input('Enter make of auto: ')
self.model = input('Enter model of auto: ')
self.color = input('Enter color of auto: ')
self.year = int(input('Enter year of auto: '))
self.mileage = int(input('Enter mileage of auto: '))
except ValueError:
# Probably happens if year/mileage entered are not numeric integers
print('You entered an incorrect type, please try again')
# Recursively start the function again, prompting user input
self.auto_attributes()
def __str__(self):
# This string tuple will be returned if an instance of Automobile is
# being used as a string type argument (such as a print statement)
return str((self.make, self.model, self.color, self.year, self.mileage))
class Inventory:
def __init__(self, starting_count=0, starting_inv={}):
""" Initialize a new Inventory object """
self.count = starting_count # count is 0 unless otherwise specificed
self.inv = starting_inv # Empty inventory unless otherwise specified
def __str__(self):
# Return a string representation of the inventory dictionary
return str(self.inv)
def add_auto(self, automobile):
""" Function to add a new Automobile object's attributes
to the inventory. """
if type(automobile) == Automobile:
# Only add to inventory if automobile is an object of class Automobile
# This ensures automobile has all the correct attributes and no funny
# business.
self.count = self.count + 1
self.inv[self.count] = vars(automobile)
# The vars() function returns a dictionary containing all the class
# attributes. {'make': '...', 'model': '...'', 'color': '...',
# 'year': '...', 'mileage': '...'} in this case.
print(self.inv)
else:
# Else clause covers an automobile input other than an Automobile class
# object by asking if a new Automobile object should be created and
# added to the inventory.
print('automobile must be an object of class Automobile')
new_car_question = input('Would you like to create a new Automobile\
instance and add it to the inventory?\n(Y)es/(N)o: ')
if new_car_question[0].lower() == 'y': # If the first letter is Y/y
new_car = Automobile()
# Recursively call the function again from the top using the
# newly created Automobile object as the argument
self.add_auto(new_car)
else:
print('Inventory has not been updated')
def remove_auto(self, inventory_id):
""" Function to remove an automobile from the inventory """
if inventory_id in self.inv.keys():
# Check if the ID supplied is in the inventory
print(f"Are you sure you'd like to remove entry {inventory_id},\n\
{self.inv[inventory_id]}\nfrom the inventory?")
answer = input('(Y)es/(N)o: ')
if answer[0].lower() == 'y':
del self.inv[inventory_id] # Delete the dictionary entry
print(f'Inventory item with ID {inventory_id} successfully removed.')
else:
print('Inventory has not been modified')
else:
print('ID supplied was not found in the inventory')
def modify_auto(self, inventory_id):
""" Function to modify an existing inventory item """
if inventory_id in self.inv.keys():
# Check if the ID supplied is in the inventory
answer = input(f"Would you like to modify item?\n{self.inv[inventory_id]}\
\n(Y)es/(N)o: ")
if answer[0].lower() =='y':
try:
ref = self.inv[inventory_id].copy()
# It's important that ref is a copy, otherwise these
# operations would immediately alter the actual inventory
# entry
ref['make'] = input(f"Make: {ref['make']} --> ")
ref['model'] = input(f"Model: {ref['model']} --> ")
ref['color'] = input(f"Color: {ref['color']} --> ")
ref['year'] = int(input(f"Year: {ref['year']} --> "))
ref['mileage'] = int(input(f"Mileage: {ref['mileage']} --> "))
self.inv[inventory_id] = ref
print(f"Successfully updated ID: {inventory_id} to \n{self.inv[inventory_id]}")
except ValueError:
print('You entered an incorrect type, please try again')
self.modify_auto(inventory_id)
else:
print('Inventory has not been modified')
else:
print('ID supplied was not found in the inventory')
To use these classes we just need to make some objects from them:
# Let's pretend I saved the above file in the working directory
# as auto_classes.py
# I'm using * imports for simplicity but know it's not recommended
# to do this in production
>>>from auto_classes import *
# Create an instance of Inventory for use
>>> inventory = Inventory()
# We'll create a new automobile object too while we're at it
>>> car_one = Automobile()
Enter make of auto: Ford
Enter model of auto: Mustang Shelby GT350
Enter color of auto: Black
Enter year of auto: 2018
Enter mileage of auto: 1200
# test that it worked
>>> vars(car_one)
{'make': 'Ford',
'model': 'Mustang Shelby GT350',
'color': 'Black',
'year': 2018,
'mileage': 1200}
# Let's check our inventory first
>>> print(inventory) # should be an empty dictionary
{}
# Let's add car_one to the inventory object
>>> inventory.add_auto(car_one)
{1: {'make': 'Ford', 'model': 'Mustang Shelby GT350', 'color': 'Black', 'year': 2018, 'mileage': 1200}}
# Let's modify it now
>>> inventory.modify_auto(1) # inventory ID = 1
Would you like to modify item?
{'make': 'Ford', 'model': 'Mustang Shelby GT350', 'color': 'Black', 'year': 2018, 'mileage': 1200}
(Y)es/(N)o: yes
Make: Ford --> Toyota
Model: Mustang Shelby GT350 --> Avalon
Color: Black --> White
Year: 2018 --> 2007
Mileage: 1200 --> 175000
Successfully updated ID: 1 to
{'make': 'Toyota', 'model': 'Avalon', 'color': 'White', 'year': 2007, 'mileage': 175000}
# Check our modified inventory
>>> print(inventory)
{1: {'make': 'Toyota', 'model': 'Avalon', 'color': 'White', 'year': 2007, 'mileage': 175000}}
# Let's add one more car to the inventory
>>>inventory.add_auto('I am feeling lazy')
automobile must be an object of class Automobile
Would you like to create a new Automobile instance and add it to the inventory?
(Y)es/(N)o: yesssssss
Enter make of auto: Honda
Enter model of auto: Accord
Enter color of auto: Silver
Enter year of auto: 2010
Enter mileage of auto: 75000
{1: {'make': 'Toyota', 'model': 'Avalon', 'color': 'White', 'year': 2007, 'mileage': 175000}, 2: {'make': 'Honda', 'model': 'Accord', 'color': 'Silver', 'year': 2010, 'mileage': 75000}}
#Finally, let's remove the Avalon from the inventory object because it broke down
>>> inventory.remove_auto(1)
Are you sure you'd like to remove entry 1,
{'make': 'Toyota', 'model': 'Avalon', 'color': 'White', 'year': 2007, 'mileage': 175000}
from the inventory?
(Y)es/(N)o: Y
Inventory item with ID 1 successfully removed.
I left out a few things for you to figure out like searching the inventory and saving it to a txt file but I hope this helps. Things to keep in mind:
- Classes are like blueprints for building objects
- An object needs to be created (instantiated) before class methods/variables can be used
- Variable scope needs to be kept in mind.
- Classes and functions each have their own internal scope for variables defined within them.
- the
global
keyword can be used to specifically access global variables from within a class or function to avoid a new instance of the variable being created. But try to stay out of the habit of using global variables, it’s often frowned upon.
- Think critically about what methods belong to which class (object).
I’m sure this is a little different from the book, but I hope this helps you out anyway. Good luck!