Why am I getting 'UnboundLocalError: local variable 'value' referenced'? - python

I just learned what classes are today so I'm hoping this doesn't look too bad. 'model' refers to the model year.
class Car:
def __init__(self, model=0, price=0, year=0):
self.model = model
self.price = price
self.year = year
def depreciate(self, price):
rate = 0.15
age = da_car.model - da_car.year
for i in range(age):
value = price * rate
price = value
return value
def print_info(self):
print('Car\'s infortmation: \n Model year: ', da_car.model ,' \n Purchase price: ', da_car.price,' \n Current value: ', car_value)
da_car = Car()
da_car.model = int(input())
da_car.price = int(input())
da_car.year = int(input())
car_value = da_car.depreciate(da_car.price)
da_car.print_info()
I'm trying to return the depreciated value of the input price after x amount of years. Not sure why I'm getting this error. I tried making 'value' global but that did not work.

The issue is that the variable "value" actually is defined within the "for" loop, and that is its scope. So that variable and its information is not known outside of that loop. The program would most likely want/need a definition of that variable that would be visible within the class. With that in mind and testing out the code I made a few tweaks to the program. Following is a revised version of your program.
class Car:
def __init__(self, model=0, price=0.0, year=0):
self.model = model
self.price = price
self.year = year
self.value = price # This will be calculated later
def depreciate(self):
rate = 0.15
age = self.year - self.model # Correct age calculation
self.value = self.price # Initialize the value to the initial price
for i in range(age):
self.value = float(self.value - self.value * rate)
#price = value
return self.value
def print_info(self):
# The function within a method would not print data for a specific class (e.g. "da_car")
print('Car\'s infortmation: \n Model year: ', self.model ,' \n Purchase price: ', self.price,' \n Current value: ', self.value)
da_car = Car()
dx_car = Car()
print("First car statistics")
da_car.model = int(input("Model year: "))
da_car.price = float(input("Price: "))
da_car.year = int(input("Current year: "))
car_value = da_car.depreciate()
da_car.print_info()
print("Second car statistics")
dx_car.model = int(input("Model year: "))
dx_car.price = float(input("Price: "))
dx_car.year = int(input("Current year: "))
car_value = dx_car.depreciate()
dx_car.print_info()
Following are some key points.
In order to make the value variable pertinent to the depreciation function and to the car printing function, it was added as an attribute to the class.
In the various class functions, it would not be appropriate to use object specific variables in the calculations; rather class defined variables make more sense - so references to a specific object were changed to the "self" reference.
In testing I noticed the calculation for age was incorrect - the two variables needed to be reversed.
A second object definition was added to accentuate the point of usage of classes and objects and attempt to clarify why one would not want to use object specific variables in a class function.
With those revisions in place, a test run of the program was done.
#Dev:~/Python_Programs/Cars$ python3 Cars.py
First car statistics
Model year: 2020
Price: 32000
Current year: 2025
Car's infortmation:
Model year: 2020
Purchase price: 32000.0
Current value: 14198.57
Second car statistics
Model year: 2018
Price: 44000
Current year: 2025
Car's infortmation:
Model year: 2018
Purchase price: 44000.0
Current value: 14105.391884375002
Some print formatting would be beneficial for the current value but this should highlight the setup and use of objects based upon class definitions.
Give that a try and see if it meets the spirit of your project.

Related

How to get a total from with "Class" in python, then calling it into another file main()?

My assignment is : Assume you sell t-shirts ( or any other item), and all t-shirts cost the same, they all have the same price
Define a class called Sale. The first line of the constructor would only have 3 arguments: self, item and quantity. In addition, the constructor has an attribute for the price and an attribute to hold the total for the sale.
The program assumes the same price for every item, so you can initialize the price in init using the price of your choice. Just like we did with the car example I showed in the lecture, where the speed attribute was initialized to zero in init, you could initialize total at total to zero
The class should have 4 methods to:
A method to calculate the total
A method to return the total
A method to return the item
A method to return quantity
The program importing the file with this class needs to create an instance of the Sale class. Assuming, the file with the class definition is sale.py and the class is Sale, it would look something like this
new_sale = sale.Sale('Men medium blue', 10)
When I run the program that creates the class instance, assuming the price in the class was set to 9.99, the output would look something like this
new_sale = sale.Sale('Men medium blue', 10)
The total for 10 t-shirts Men medium blue is $ 99.9
'''class Sale:
def __init__(self,item,quantity):
self.item=item
self.quantity=quantity
self.total=self.price*self.quantity
self.price=10
def get_item(self):
return self.item
def get_quantity(self):
return self.quantity
def get_total(self):
return self.total
'''
This is my main function in another file, I'm trying to get the user input quantity to multiply by the set price ($10) in Class
'''
import sale
def main():
itemQ=input("Please enter type of t-shirt: ")
quanT=int(input("Please insert number of t-shirt you wish to buy: "))
theSale= sale.Sale(itemQ, quanT)
print("The item is ", theSale.get_item(), " and a quantity of ", theSale.get_quantity(), "and total of ", theSale.get_total())
main()
'''
A couple minor changes should get it working:
# sale.py
def __init__(self, item, quantity):
self.item=item
self.quantity=quantity
self.price=10
self.total=self.price*self.quantity # you have to define price before you use it to calculate the total
# add these two lines at the end of you main .py file
if __name__ == '__main__':
main()
See python docs on main method: main

Python Programming with Class Definition

This is my code so far, the error I'm having so far is (name 'person' is not defined) on line person.name = name, I'm literally stuck & trying to figure out what is the issue/error since my code has to be based on the question I wrote below.I'm not sure if the remaining of my code has any errors since it is detecting that error first.
from datetime import date
class person:
pass
def create_person(name, height, birthdate):
person.name = name
person.height = height
get_age = birthdate
return person
def get_age(person):
birthdate = person.birth
today = date.today()
subyear = 0
if today.month < birthdate.month or (today.month == birthdate.day and today.day <= birthdate.day):
subyear = 1
person.age = (today.year - (birthdate.year + subyear))
return person.age
def get_description(person):
return person.name + ' is ' + str(person.height) + ' cm high and is ' + str(get_age(person)) + ' years old'
def main():
birthdate = date(1976, 8, 14)
person = create_person('Michael', 190, birthdate)
print(get_description(person))
This is the question:
Write a class definition for the Person class and write user-defined
functions with these function headers:
def create_person(name, height, birthdate):
# Return a a new person object with the given name, height and birthdate.
# - name is a str
# - height is an int object in centimetres
# - birthdate is a date object from the
# module datetime
def get_age(person):
# Return the age of the person in years.
For example, assume today's date is June 12, 2018. if Mary was born on
June 4, 2017, then Mary's age is 1. However, if Bob was born on June
14, 2018, then Bob would not have had a first birthday yet so the age
is 0.
def get_description(person):
# Return a string object of the form: Name is
# N cm high and is M years old, where N and M
# are integers
For example, Michael is 190 cm high and is 43 years old or Samantha is
95 cm high and is 4 years old.
def main():
# Create a person named 'Michael', with height
# 190 cm, who was born on August 14, 1976 and
# output a description of this individual.
If you use a function from an imported module when writing your
function, you usually declare the import statement at the top of your
code.
Here is a sample run of a main program that just calls the main
function.
Michael is 190 cm high and is 43 years old.
This is a hint I currently received:
Use the date class from the datetime module to represent a date. An
object whose type is date, has attributes: year, month and day that
you can use to compute the age of a Person.
To compute the current age of a person, you will need to first compute
today's date. There is a method in the date class of the datetime
module that creates a new date object that represents the current
date. The name of this method is today. However, the special argument
of this method must be the date class itself, instead of a particular
object whose type is date. A method that is applied to a class object
instead of to an instance of that class is called a class method.
Therefore, to create the current date you can use the expression:
date.today()
since after importing the date class from the datetime module, the
identifier date is bound to the date class object.
To compute the age you can just subtract the year attribute of the
birthdate from the year attribute of the current date. However, you
will also need to check whether the person has already had their
birthday yet this year and if not, subtract one year
Have Person create its own attributes
class Person:
def __init__(self, name, height, birthdate):
self.name = name
self.height = height
self.birthdate = birthdate
# why someone would write such a function is beyond me, but...
def create_person(name, height, birthdate):
return Person(name, height, birthdate)
# test
p = create_person('myname', 100, '23-23-23')
print(p.name)
This produces
myname
Now the other functions will have a class instance they can use.
If you have a problem with any one of the functions, that's best posted in another question that focuses just on that problem. (removing functions / methods not needed to demonstrate the problem).

How do I dynamically name an instance or change the attributes of all instances in a class?

I am trying to model population growth using individual agents, but have already run into trouble with the basic skeleton of the model.
I have a class to hold individuals
class Individual:
"""These are individuals"""
list = []
def __init__(self, name, sex, dob):
self.name = name
self.sex = sex
self.dob = dob
self.list.append(name)
def __str__(self):
return "name is {}, sex is {}, age is {}" .format(self.name, self.sex, curyear - self.dob)
and I instantiate new individuals through
def birth():
global person
person = Individual((next(name)), randsex(), curyear)
The basic growth loop is
for i in range(totalyears):
curyear = curyear + 1
if curyear - person.dob == 18:
birth()
else:
pass
The problem seems to be that
if curyear - person.dob == 18:
birth()
is only ageing and checking the last instance of Individual that's created.
print (Individual.list) shows that my final population = starting population + total years /18 and print (str(person)) too seems to confirm this.
I think this is because my birth() function basically names each new instance 'person', so whenever I use person.whatever it references the latest instance created. It seems to me that there are two possibilities.
A) Dynamically give each new instance a unique name, and use a list to reference each of these instances' attributes in the growth loop.
B) Add an age instance attribute and figure out how to change this for all members of the class.
I don't know if either is possible, or how to do them. I would appreciate any advice and examples!

If = 1 then answer is day shift else answer is night shift

with this program the outcome should display employee name, number , shift (day or night based on the number imputed) and hourly pay rate.
I've tried a few different ways and can "almost" get the desired results. Any assistance would be appreciated.
# This Employee class holds general data about employess and will
# end up as the superclass for this example.
class Employee:
#__init__ method initialzes the attributes.
def __init__(self, emp_name, emp_number):
self.__emp_name = emp_name
self.__emp_number = emp_number
# The set_emp_name method gets the employee name.
def set_emp_name(self, emp_name):
self.__emp_name = emp_name
# The set_emp_name method gets the employee number.
def set_emp_number(self, emp_number):
self.__emp_number = emp_number
# The get_emp_name method returns the employee name.
def get_emp_name(self):
return self.__emp_name
# The get_emp_number method returns the employee number.
def get_emp_number(self):
return self.__emp_number
# The ProductionWorker class holds the general data from superclass Employee
# as well as Employee shift time and pay rate making it a subclass
# of Employee.
class ProductionWorker(Employee):
# __init__ method initializes the attributes.
def __init__(self, emp_name, emp_number, shift, payrate):
# Call the superclass
Employee.__init__(self, emp_name, emp_number)
self.__shift = shift
self.__payrate = payrate
# The set_shift method get employee shift.
def set_shift(self, shift):
self.__shift = shift
# The set_payrate method gets employee hourly pay rate.
def set_payrate(self, payrate):
self.__payrate = payrate
# The get_shift method returns the employee shift.
def get_shift(self):
if self.shift == 1:
self.shift = 'Day shift'
elif self.shift == 2:
self.shift = 'Night shift'
return self.__shift
# The get_payrate method returns the employee hourly pay rate.
def get_payrate(self):
return self.__payrate
# This program will test the Employee superclass and ProductionWorker subclass
# by returning and displaying the gathered information.
import sys
# Get the Employee info.
emp_name = input('Employee Name: ')
emp_number = input('Employee Number: ')
shift = float(input ('Shift Number 1 or 2: '))
payrate = input('Hourly Pay Rate: $')
# Determine True or False for mailing list.
#if shift == 1:
#print('Day')
#else:
#print ('Night')
# Create an instance of the ProductionWorker class.
my_productionworker = ProductionWorker(emp_name, emp_number, shift, payrate)
# Display the object's data.
print('Employee Information')
print('---------------------')
print('Employee Name:', my_productionworker.get_emp_name())
print('Employee Number:', my_productionworker.get_emp_number())
print('Shift:', my_productionworker.get_shift())
print('Hourly Pay Rate:$', my_productionworker.get_payrate())
In your method
def get_shift(self):
if self.shift == 1:
self.shift = 'Day shift'
elif self.shift == 2:
self.shift = 'Night shift'
return self.__shift
you're mixing up .shift and .__shift In the if and elif, it should be .__shift and in the assignments it should be just shift (a local variable, not a member variable) and then you should return that local variable (or maybe just return directly from inside the if and elif, depending on how you feel about multiple exit points).
Also, it's a good practice to include a final else in your if / elif, possibly something like this:
else:
shift = 'Cannot convert {} to a valid shift.'.format(self.__shift)
or
else:
raise Exception('Invalid shift value {}.'.format(self.__shift)
which will alert you to the fact that you fell through all the valid options, and give you a hint as to what value is causing the problem.
BTW, you should not be using double underscore variables in this way and, in general, should not try to write Java code in Python. I'd get rid of the getters and setters and just read and write the member values directly.

Python: Class and SubClass - Why won't in recognize the subclass

I am trying to create a class that contains the salary and bonus attributes and another that contains the name and idnum attributes. With a small program that asks if the shift has met goal for the year and then figures the total income for the shift supervisor for the year. Every time I try I get:
File "C:\Python33\12-2.py", line 53, in main
shift1 = Shiftsupervisor.Employee('28000.0','2240.0','Ian McGregor', 'S10001' )
AttributeError: type object 'Shiftsupervisor' has no attribute 'Employee'
What have I done wrong??
# This creates two classes - ShiftSupervisor & Employee
# The program then tells us what the annual income is
# This creates a class of Super Class Shiftsupervisor which contains salary, & bonus \
figures
class Shiftsupervisor:
#Initialize the Shiftsupervisor attributes
def __init__(self, salary, bonus):
self.__salary = salary
self.__bonus = bonus
# creates the mutator for the attributes
def set_salary(self, salary):
self.__salary = salary
def set_bonus(self, bonus):
self.__bonus = bonus
# returns the attributes
def get_salary(self):
return self.__salary
def get_bonus(self):
return self.__bonus
#Create the subclass of employee which holds the name & idnum
#Initialize the employee attributes
class Employee(Shiftsupervisor):
def __init__(self, salary, bonus, name, idnum):
Shiftsupervisor.__init__(self, salary, bonus)
#Initialize the employee new attributes
self.__name = name
self.__idnum = idnum
#creates the new mutator for name & id
def set_name(self, name):
self.__name = name
def set_idnum(self, idnum):
self.__idnum = idnum
# new method returns the name & id
def get_name(self):
return self.__name
def get_idnum(self):
return self.__idnum
#This program take info from the two classes and gives
# the total income for the Shift Supervisor
#Creates the shift supervisor objects
def main():
shift1 = Shiftsupervisor.Employee('28000.0','2240.0','Ian McGregor', 'S10001' )
shift2 = Shiftsupervisor.Employee('29500','2360.0','Brian Bory', 'S20202' )
shift3 = Shiftsupervisor.Employee('28750.0','2300.0''Finn McCool', 'S30045' )
def total_income():
if production == 'y' or 'Y':
return __salary + __bonus
else:
return __salary
#Ask the Question - Did they make production quota
production = input('Did Shift 1 make quota this year? Type Y for yes ' )
#Print the income
print(shift1.get_name(),'s Total income is: $', format(total_income, \
',.2f'), sep='')
#Ask the Question - Did they make production quota
production = input('Did Shift 2 make quota this year? Type Y for yes ' )
#Print the income
print(shift2.get_name(),'s Total income is: $', format(total_income, \
',.2f'), sep='')
#Ask the Question - Did they make production quota
production = input('Did Shift 3 make quota this year? Type Y for yes ' )
#Print the income
print(super3.get_name(),'s Total income is: $', format(total_income, \
',.2f'), sep='')
#call the main function
main()
Your code has the following problems:
I think it'd be better have ShiftSupervisor be a subclass of Employee. Unless I'm misunderstanding, a shift supervisor is a kind of employee, so employee is the base class. A shift supervisor might have additional attributes that specialize the Employee class. I've added the shift_number attribute to demonstrate this.
Your main method only creates the employees, but doesn't ever do anything with them.
Your total_income method is a bit confused. Remember, __salary and __bonus are attributes of an object. You have do always use the form instance.attribute in order to get access to those.
You don't need getters and setters in Python. The convention is to keep them normal fields that are meant to be publicly accessible, and use properties if it turns out you do need more complex accessing logic.
The salary and bonus shouldn't be a string -- they're numeric values.
Taken together, your new code might look something like this:
class Employee:
def __init__(self, salary, bonus, name, idnum):
self.salary = salary
self.bonus = bonus
self.name = name
self.idnum = idnum
class ShiftSupervisor(Employee):
def __init__(self, salary, bonus, name, idnum, shift_number):
super().__init__(salary, bonus, name, idnum)
self.shift_number = shift_number
def main():
shift1 = ShiftSupervisor(28000.0, 2240.0, 'Ian McGregor', 'S10001', 1)
shift2 = ShiftSupervisor(29500, 2360.0, 'Brian Bory', 'S20202', 2)
shift3 = ShiftSupervisor(28750.0, 2300.0, 'Finn McCool', 'S30045', 3)
find_income(shift1)
find_income(shift2)
find_income(shift3)
def find_income(employee):
production = input('Did shift {0} make quota this year? Type Y for yes '.format(employee.shift_number))
if production.lower() == 'y':
total_income = employee.salary + employee.bonus
else:
total_income = employee.salary
print("{0}'s Total income is: ${1}".format(employee.name, total_income))
main()
I'm also getting the feeling that you're entangling a shift and an employee in some way that you shouldn't be, though I'm quite able to put my finger on it. A shift might have more than one employee, and an employee could work multiple shifts, though this'll definitely depend based on what problem you're trying to solve.

Categories