This question already has answers here:
How do I create variable variables?
(17 answers)
Closed 8 years ago.
I have tried using list and/or dictionaries to store the objects that I create, but my attempts have failed.
A reasons to use a list or a dictionary is to have python keep a reference to the object so as prevent the garbage collection component from discarding our object. My issues seems to be more with the initialization of the object itself, and with naming the object.
My script takes data out of a database and then automatically creates objects for each item in the list, in our case, employees.
Here is my class:
class Employee:
empCount = 0
def __init__(self, employee_id, name, age):
self.employee_id = employee_id
self.name = name
self.age = age
Employee.empCount += 1
def display_employee_count(self):
print("Total Employee %d" % Employee.empCount)
def display_employee(self):
print("Employee ID : ", self.employee_id,
" First name : ", self.name,
' Age : ', self.age)
I know that to create an object I would call
joe1883 = Employee('joe1883', 'Joe', 21)
To display the objects attributes I would
joe1883.display_employee()
which yields:
Employee ID : joe1883 First name : Joe Age : 21
My question is, how do I do this through a loop ?
# Data set has, employee id, first name, and age
my_list = [['joe1883', 'joe', 21],
['bob1492', 'bob', 22],
['frank1889','frank',34]]
for names in my_list:
employee_id = names[0]
name = names[1]
age = names[2]
#print("Employee ID : " + employee_id + " First name : " + name + ' Age : ' + str(age))
# This is the line that creates my error !
employee_id = Employee(employee_id, name, age)
If I insert this line into the loop statement
employee_id = Employee(employee_id, name, age)
And then call
joe1883 = Employee('joe1883', 'Joe', 21)
I get a #NameError: name 'joe1883' is not defined.
You need to keep a reference to an object around not just so it isn't garbage-collect, but also so you can reference it. The reference can be by giving it a variable name, like joe1883, or it can be by storing the object in a container, like a list or dictionary.
If you put it in a list, each element in the list can be reference with an integer index, such as employees[42]. To find an employee in such a container you will need to search through potentially all of them, by index, until you find the one you want.
If you want to find an employee quickly given their id, you should store them in a dictionary instead, then you could do something like employees['joe1883'] to directly access one of them.
Since you don't know kind of container an Employee instance will be put in, if any, it makes little sense to keep an empCount in the class. If you put a bunch of them in a list or dictionary, and ever need to know how many, you can find that by using the built-in len() function on the container object, i.e. len(employee_list) or len(employee_dict).
class Employee:
def __init__(self, id, name, age):
self.id = id
self.name = name
self.age = age
def display(self):
print("Employee ID : ", self.id,
" First name : ", self.name,
' Age : ', self.age)
# create a single employee object and name it joe1883
joe1883 = Employee('joe1883', 'Joe', 21)
joe1883.display()
# now create a list of employees by converting dataset
# my_list into a list of Employee instances named employees
# dataset
my_list = [
['joe1883', 'joe', 21],
['bob1492', 'bob', 22],
['frank1889','frank', 34],
]
employees = [Employee(item[0], item[1], item[2]) for item in my_list]
# display each employee in list
for employee in employees:
employee.display()
# or you could do it this (non-pythonic) way:
for i in range(len(employees)):
employees[i].display()
# to print an employee with a given id
# you'd need to search for it in the list
for employee in employees:
if employee.id == 'joe1883':
employee.display()
break # found, so stop loop
# Here's how to create a dictionary of employees by converting dataset
# my_list into Employee instances keyed by their id
employees = {item[0]: Employee(item[0], item[1], item[2]) for item in my_list}
# look one of them up
if 'joe1883' in employees:
employees['joe1883'].display()
If I understand your question correctly, you are trying to create a set of objects-employees based on the list with the arguments for each of the objects.
I modified/simplified your code a little bit and this is working fine:
class Employee:
empCount = 0
def __init__(self, employee_id, name, age):
self.employee_id = employee_id
self.name = name
self.age = age
Employee.empCount += 1
def display_employee_count(self):
print("Total Employee %d" % Employee.empCount)
def display_employee(self):
print("Employee ID : {0} First name : {1} Age : {2}".format(self.employee_id, self.name,self.age))
my_list = [('joe1883', 'joe', 21), ('bob1492', 'bob', 22), ('frank1889', 'frank', 34)] # in this format arguments will be easier to pass as parameters to your class constructor
list_of_employees = [] # list where you can put created objects
for emp in my_list:
list_of_employees.append(Employee(*emp)) # now you just pass your tuple of arguments like that
for emp in list_of_employees: #looping through the list with objects you created and printing results
emp.display_employee()
#eduard You are doing 2 things wrong.
1) the indentation is bad, so the methods of the class Employee are not inside the class.
2) You are not storing the objects anywhere.
Id suggest you to do it in this way:
employ_dic={}
class Employee:
def __init__(self, employee_id, name, age):
self.employee_id = employee_id
self.name = name
self.age = age
employ_dic[employee_id]=self
def display_employee(self):
print '''Employee ID: {0}, First Name: {1}, Age: {2}'''.format(self.employee_id, self.name, self.age)
lists = [['joe1883', 'joe', 21],['bob1492', 'bob', 22],['frank1889','frank',34]]
for list in lists:
employee_id = Employee(list[0], list[1], list[2])
employ_dic['joe1883'].display_employee()
# to display the count:
print len(employ_dic)
Related
I have created a class that takes name,id number and salary for each object. inside the class there are functions for adding or deduction of the salary and showing the status for each employee:
class emp():
def __init__(self,name,id_num,salary):
self.name=name
self.id=id_num
self.s=salary
def bounus(self,bon):
self.s+=bon
print(" the empolyee %s got a raise of %s"%(self.name,bon))
def ded(self,d):
self.s-=d
print(" the empolyee %s got a deduction of %s"%(self.name,d))
def show(self):
s="the employee {} with id number {} has a salary of {}".format(self.name,self.id,self.s)
print(s)
so I wanted to create a number of objects of my chioce using "range" function in the "for" loop as the following:
for i in range(1,3) :
o=str(input("Enter the employees number %s name\n"%i))
p=input("Enter his\her id number\n")
q=input("Enter his\her salary\n")
ai=emp(o,p,q)
ai.show()
in that way, it loops through 1 and 2 creating objects a1 and a2 and it worked but when I try to show them outside the loop as the following:
a1.show()
it says,a1 is undefined although I could show them inside the loop , how can I store the objects so I can show or apply functions on them after looping .thanks
The i in ai does not get processed as a seperated variable, it just becomes one whole ai.
Instead, you should make a list a, which you can access with a[i].
a = []
for i in range(2) : # Slight change to start at i=0
o=str(input("Enter the employees number %s name\n"%i))
p=input("Enter his\her id number\n")
q=input("Enter his\her salary\n")
a.append(emp(o,p,q))
a[i].show()
Selcuk identified your issue, but here is a code snippet based on your code that may help you conceptualize his advice:
new_employees = []
for i in range(1,3):
name = input("Enter the employees number %s name\n" %i)
id_num = input("Enter his\her id number\n")
salary = input("Enter his\her salary\n")
employee = emp(name, id_num, salary)
employee.show()
new_employees.append(employee)
At the end of the loop you will now have a list of new employees that you can do other things with. So, per your comment assume you want to deduct $25 from the salary of on the employee with the employee id of 5. You could something like this if you didn't want to get fancy:
target_employee = None
for employee in new_employees:
if employee.id == 5:
target_employee = employee
break
if target_employee:
target_employee.ded(25)
Here is another way that auto-creates a name for each employee the way you intended and stores that name and the employee object in a dictionary. Each employee can then be called by his name from outside the loop with full access to all the class methods. Also class names should always be capitalized. Object names are in lower case:
class Emp():
def __init__(self, name, id_num, salary):
self.name = name
self.id = id_num
self.s = salary
def bonus(self, bon):
self.s += bon
print("The empolyee %s got a raise of %s" % (self.name, bon))
def ded(self, d):
self.s -= d
print("The empolyee %s got a deduction of %s" % (self.name, d))
def show(self):
s = "The employee {} with id number {} has a salary of {}".format(self.name, self.id, self.s)
print(s)
employees = {}
for i in range(1, 3):
o = input("Enter the employees number %s name\n" % i)
p = input("Enter his\her id number\n")
q = int(input("Enter his\her salary\n"))
emp = Emp(o, p, q)
name = "a" + str(i)
employees[name] = emp
employees["a1"].show()
employees["a2"].bonus(500)
employees["a2"].ded(200)
employees["a2"].show()
The first mistake you have done is declaring the class inside the for loop. The scope of the object is limited to the for loop and will be destroyed after the loop and moreover you cannot store all the values wrt to the loop as every time a loop is run the new object will be invoked destroying all the previous one hence us the list to append them and try
I have a simple program that takes user name and age using user input. How can I store the data on dictionary and update the data if another user put new name and age. Here is my sample code. I don't know if I'm doing it right.
class Name:
data = {}
num_employee = 0
def __init__(self, name, age):
self.name = name
self.age = age
Name.num_employee += 1
#classmethod
def user_in(cls):
name = input('Enter name: ')
age = int(input('Enter age: '))
return cls(name, age)
def show(self):
Name.data = {'name': self.name, 'age': self.age}
return Name.data
employ = Name.user_in()
employ2 = Name.user_in()
print(Name.num_employee)
print(employ.show())
Every instance of a Name class would be a person with name and age. Now i'm not getting if you're supposing an employee can have more than one name (and this is why you need a dictionary) or you simply need an object to collect information about every user.
If you want to mantain the input inside of the class move it to the constructor, that is __init__ method.
I would use another object such as a list to collect the set of users.
I also added two method to the class Person allowing user to modify age and name with a new input.
class Person:
def __init__(self):
self.name = input('Enter name: ')
self.age = int(input('Enter age: '))
def show(self):
data = {'name': self.name, 'age': self.age}
return data
def change_name(self):
self.name = input('Update name: ')
def change_age(self):
self.age = int(input('Update age: '))
persons = []
employ = Person()
employ2 = Person()
# add employ to the list
persons.append(employ)
persons.append(employ2)
# to show information
print(len(persons)) # len of the list is the number of employees
print(employ.show())
# to change employ1 name you can do
employ.change_name()
# to change employ2 age do
employ2.change_age()
I have a function where it call another method and returns 3 values, I have to store that in a dict, when the same function is called back, I have to check the dict if the same value already stored in dict, if it is I have to return that, else load new set of values.
IDS = {}
def get_ids(id):
if id in IDS:
return IDS[id], IDS[name], IDS[salary]
else:
id, name, salary = load_ids(id)
IDS['id'] = id
IDS['name'] = name
IDS['salary'] = salary
return id, name, salary
here I am replacing the first stored ids, but I have to add the new values with new ids, load_ids do some calculation and return some values
you can get that for free using functools.lru_cache:
from functools import lru_cache
#lru_cache(maxsize=512)
def get_ids(id, name, salary):
id, name, salary = load_ids(id, name, salary)
return id, name, salary
You could do something like this, if you want to continue on your example.
# Example
IDS = {1: {'name': 'Peter', 'salary': 200000}}
def get_ids(id):
if id in IDS:
return id, IDS[id]['name'], IDS[id]['salary']
else:
name, salary = load_ids(id)
IDS[id] = {}
IDS[id]['name'] = name
IDS[id]['salary'] = salary
return id, name, salary
I've never used classes before and I am trying to get a general understanding of how they work with the code example I have below. Im having issues referencing one of the names i define for a class. i just want the program to print out a list of the employee names and salaries stored in the list when the option 2 is entered but it gives me the following error:
Traceback (most recent call last):
File "C:\Scott Glenn\Misc\classes.py", line 31, in
employees[i].displayEmployee
AttributeError: 'str' object has no attribute 'displayEmployee'
class Employee:
'Common base class for all employees'
empCount = 0
def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1
def displayCount(self):
print "Total Employee %d" % Employee.empCount
def displayEmployee(self):
print "Name : ", self.name, ", Salary: ", self.salary
def AddNewEmployee():
NewEmployee = raw_input("What is the Employees name: ")
employees.append(str(NewEmployee))
NewEmployeeSalary = raw_input("What is the Employees salary: ")
NewEmployee = Employee(NewEmployee, NewEmployeeSalary)
return employees
#=============================================================================
employees=[]
while(1):
print'Welcome to the Employee Database!'
option = raw_input('Please select 1 to add new employee or 2 to display all current employees: ')
if option=='1':
employees.append(AddNewEmployee())
if option=='2':
for i in range(0,len(employees)):
employees[i].displayEmployee
The AddNewEmployee function is wrong. It's returning a list of a single string when you want to be returning a single object of your custom type Employee.
It should be more like this:
def AddNewEmployee():
#string variable to hold name
NewEmployeeName = raw_input("What is the Employees name: ")
#why make a list? you are appending the result of this function to that list
#employees.append(str(NewEmployee))
#plus this is adding the employee before he's even been created
NewEmployeeSalary = raw_input("What is the Employees salary: ")
#construct using name string and salary string
NewEmployee = Employee(NewEmployeeName, NewEmployeeSalary)
return NewEmployee #return Employee object (to be appended later)
Additionally, you are trying to access displayEmployee() as a field of your class, instead of as a method. Fields don't have parenthesis and methods do (so they can take parameters, though in this case the parenthesis are empty as no parameters are passed).
Finally, note that raw_input returns a string so you should cast to float if that is what you wish your NewEmployeeSalary to be. (Right now it's a string.)
I've updated your code below. The main issue that I saw that you had was that you were using 'employees' as a global and appending to it twice. I moved it out of the AddNewEmployee() function and had that return the new employee which is then appended to 'employees'
Also you weren't calling '.displayEmployees'
Notice the the parentheses that I added to the end.
I hope this helps!
class Employee(object):
'Common base class for all employees'
empCount = 0
def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1
def displayCount(self):
print "Total Employee %d" % Employee.empCount
def displayEmployee(self):
print "Name : ", self.name, ", Salary: ", self.salary
def AddNewEmployee():
NewEmployee = raw_input("What is the Employees name: ")
NewEmployeeSalary = raw_input("What is the Employees salary: ")
NewEmployee = Employee(NewEmployee, NewEmployeeSalary)
return NewEmployee
# =============================================================================
if __name__ == "__main__":
employees = []
while True:
print'Welcome to the Employee Database!'
option = raw_input(
'Please select 1 to add new employee or 2 to display all current employees: ')
if option == '1':
employees.append(AddNewEmployee())
if option == '2':
for i in range(0, len(employees)):
employees[i].displayEmployee()
It looks like this:
I define a class:
class Boy():
def __init__(self):
self.age = input()
self.height = input()
Then I define a list with the names of the boys that I want to be object instances of the above 'class Boy':
boys = [input(), input()]
(for example: john & frank, so that boys = ['john', 'frank'])
I want now to iterate over my list 'boys' and use each name to make an object of the 'class Boy':
for value in boys:
value = Boy()
Of course, it does not work :-) but is there a way to achieve it ??
I have been using Python since 1 week, if the question sounds silly :-)
If someone could help me, will be very thankful
Thank you all for the help, I implemented the proposed solutions:
thank_you_people = ['Makoto','L3viathan','Rcynic','Pythonic','Paul Rooney', 'st.eve']
:-)
for person in thank_you_people:
print('Thank you, %s' % person)
I would highly recommend changing your class up a bit, to remove input() calls from the constructor. You could use an __init__ method that has optional arguments for age and height, and a forced one for name:
class Boy():
def __init__(self, name, age=None, height=None):
self.age = age
self.height = height
self.name = name
You then can instantiate with a name, and assign the attributes later:
boys = [Boy(input("New boy: ")), Boy(input("New boy: "))] # e.g. "John", "Frank"
for boy in boys:
boy.age = input("Age of",boy.name + "?")
boy.height = input("Height of",boy.name + "?")
edit: To have the boys in a dictionary for easier access:
boys = {}
for _ in range(2):
name = input("New boy:")
boys[name] = Boy(name)
for boy in boys:
boys[boy].age = input("Age of",boys[boy].name + "?")
boys[boy].height = input("Height of",boys[boy].name + "?")
Don't use the input function in your __init__ method, as it restricts how your Boy class can be used. Instead define a separate function that creates a Boy and pass those parameters to your Boy constructor. Then you could store your Boys in a dict, keyed by the boys name.
e.g.
class Boy():
def __init__(self, age, height):
self.age = age
self.height = height
def __str__(self):
return 'age=%d height=%d' % (self.age, self.height)
def create_boy(name):
age = int(input('enter age for %s: ' % name))
height = int(input('enter height for %s: ' % name))
return Boy(age, height)
boynames = []
while(True):
name = input('enter boy name: ')
if name == '':
break
boynames.append(name)
boys = {}
for boyname in boynames:
boys[boyname] = create_boy(boyname)
for name, boyinfo in boys.items():
print('name=%s %s' % (name, boyinfo))
Later on you could query a particular boys name like so
if 'paul' in boys:
print(boys['paul'].age)
print(boys['paul'].height)
else:
print('no boy called paul')
This isn't designed to work if you can have Boys with the same name. In that case you could have each dictionary entry hold a list of Boys and find some other parameter to distinguish between the Boys of the same name.
To not use just anything as an object name, you can use the input as keys for a dict. Something like this:
class Boy():
def __init__(self):
self.age = input()
self.height = input()
boys = [input(), input()] # this is probably a bad idea
b = {}
for boy in boys:
b[boy] = Boy()
I'd suggest to i) use a dictionary for creating variables with the name contained in a string and ii) pass age and height as args, **kwargs or *args in the class, as already suggested by Makoto. Something along these lines:
class Boy():
def __init__(self, name, age=0, height=0):
self.age = age
self.height = height
boys = ['finn', 'jake']
ages = [16, 33]
height = [165, 120]
boys_objects = {}
for i, b in enumerate(boys):
boys_objects[b] = Boy(age=ages[i], height=heights[i])
Use the zip function. You'll have to change your class constructor a little bit though.
class Boy(object):
def __init__(self, (name, age, height)):
self.name = name
self.age = age
self.height = height
Then get the input values into lists
names = ['a','b','c']
ages = [10, 20, 30]
heights = [155, 160, 165]
boys = zip(names, ages, heights)
for guy in boys:
b = Boy(guy)
print b.name, b.age, b.height
I don't know wha you want to do with the objects - but you can change that in the for loop.
EDIT: In response to the error OP is getting in the comments:
I cannot reproduce the init error. I tried with python and iPython both.
Alternatively you could try
def __init__(self, guy_tuple):
self.name = guy_tuple[0]
self.age = guy_tuple[1]
self.height = guy_tuple[2]
If that doesn't work either, you can change the constructor to take in name, age and height individually. Like is working for you.
def __init__(self, name, age, height):
self.name = name
...
then the for loop must change accordingly. Since guy is a tuple with all three elements, you'll have to get each one by index within the tuple.
for guy in boys:
b = Boy(guy[0], guy[1], guy[2])
Yes object b will be overwritten, you'll have to change it to do what you need it to do once you get the object. So after b is instantiated, pass it to another function to do what you want with it, or append it to a list. Once b is an object, you continue with the logic you want.