how to check same key present in Python Dictionary - python

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

Related

How do I take a list and parse into a list of objects in a class? (Python)

I have a class with several objects. I am supposed to take a text file, open it and parse it into a list of objects, then return the list of Entry objects
I'm struggling to understand how to convert the list I made from the file, into a list of objects.
class Entry:
def __init__(self, account_num, name, balance, phone, city):
self.account_num = account_num
self.name = name
self.balance = balance
self.phone = phone
self.city = city
def read_file(file_given):
open_file = open(file_given)
entry_obj = []
for line in open_file:
word = line.split()
entry_obj.append(word)
open_file.close()
return entry_obj
the text file I'm reading contains:
100 Alan Jones 348.17 8053564820 SLO
700 Suzy Green -14.22 8052586912 SLO
Maybe something like this should work:
def map_to_entry(line):
attribute_list = line.split()
account_num = attribute_list[0]
name = "{} {}".format(attribute_list[1], attribute_list[2])
balance = attribute_list[3]
phone = attribute_list[4]
city = attribute_list[5]
return Entry(account_num, name, balance, phone, city)
def read_file(file_given):
open_file = open(file_given)
entry_obj = []
for line in open_file:
entry_obj.append(map_to_entry(line))
open_file.close()
return entry_obj
It could be as easy as using
objList = [Entry(*li) for li in data]
But sadly, for some reason your names are split like this. Alan Jones and it creates a list like
[['100', 'Alan', 'Jones', '348.17', '8053564820', 'SLO'], ['700', 'Suzy', 'Green', '-14.22', '8052586912', 'SLO']]
therefor we will get the error, TypeError: __init__() takes 6 positional arguments but 7 were given.
So we have to join these elements.
new = []
for l in read_file():
l[1:2] = [' '.join(l[1:3])]
l.pop(2)
new.append(l)
objList = [Entry(*li) for li in new]
objList will look like.
[<__main__.Entry object at 0x7fe78db6a970>, <__main__.Entry object at 0x7fe78db6acd0>]
You can unpack all the elements during an iteration. If your names are always assumed to be First Name and Last Name, you can concatenate them before creating the Entry object. The following example is quite readable:
entries = []
for account_num, first_name, last_name, balance, phone, city in read_file('data.txt'):
name = first_name + " " + last_name
entries.append(Entry(account_num, name, balance, phone, city))
Also one-liner if you're into that:
entries = [Entry(account_num, first_name + " " + last_name, balance, phone, city) for account_num, first_name, last_name, balance, phone, city in read_file('ok.txt')]
Unpacking in python means to take an iterable with a size you know before-hand and unpack every single element into different variables. Something like:
a, b, c = ['a', 'b', 'c']
The same idea can be applied to elements in a for loop, on which element is another iterable (of a fixed size) itself, as is the case of each row in your file. This allows you to convert a list into named variables, which are usually easier to read.
If your original question was to modify the read_file function, you can use a similar idea and unpack while iterating the file:
def read_file(file_given):
open_file = open(file_given)
entry_obj = []
for line in open_file:
account_num, first_name, last_name, balance, phone, city = line.split()
name = first_name + " " + last_name
entry_obj.append(Entry(account_num, name, balance, phone, city))
open_file.close()
return entry_obj
You defined your class already, but in order to 'instantiate' (create an instance of) class objects, now you must call the class. (seen in example below as Entry(), where the () lets us know that we are calling / invoking the thing)
You definitely want to keep your arguments spelled out in the init() method, just as you have them. It's good to keep things concise and human-readable.
*edit - i changed the name args to be _first, and _last, separately. Reason below.
Note that in the below example, the loop variable line is a complete, single set of Entry data. Ergo, by using an asterisk before it, Python will look for a list (or really, any iterable) and it will automatically send each list element to the function call as its own arg.
e.g. if line == 'a b c', then Entry(*line.split()) is equivalent to Entry('a', 'b', 'c')
class Entry:
def __init__(self, account_num, name_first, name_last, balance, phone, city):
self.account_num = account_num
self.name = name_first + ' ' + name_last
self.balance = balance
self.phone = phone
self.city = city
def read_file(file_given):
open_file = open(file_given)
lines = open_file.readlines()
entry_obj = []
for line in lines:
entry_obj.append(Entry(*line.split()))
open_file.close()
return entry_obj
**edit - this, of course, assumes that we know the order of the data columns as they are received. there are much more robust ways of making this code future-proof, but I digress.

How to add data on a dictionary using different multiple user input inside a class?

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()

Having a constantly changing variable in a python loop

I'm trying to write a program that would ask for a students name, a couple other numerical values, and assign them to groups, via their numerical value, to have all groups as close to equal as possible (by taking the the highest next value in the list, and assigning it to the next group and so on).
However, I'd need to save their number to some variable, as well as their name, to then print out the group's list.
For this I'd need a variable that changes everytime the loop goes through to add another student. I'd also need to sort these number, and then somehow call back the name they corrispond to after they've been sorted into groups, and I'm not sure how to do any of these. Is there any way for this to be done, would I have to use another language?
This is the code I have so far:
from easygui import *
times = 0
name = 0
s_yn = ynbox("Would you like to enter a student?")
while s_yn == 1:
msg = "Student's Information"
title = "House Sorting Program"
fieldNames = ["Name", "Grade","Athleticism (1-10)","Intellect (1-10)","Adherance to school rules (1-10)"]
fieldValues = []
fieldValues = multenterbox(msg,title, fieldNames)
times = times + 1
ath = fieldValues[2]
int_ = fieldValues[3]
adh = fieldValues[4]
ath = int(ath)
int_ = int(int_)
adh = int(adh)
total = ath+int_+adh
s_yn = ynbox("Would you like to enter a student?")
I believe it would be nice to create a Student class that holds all variables associated with a student. Then you could add each student to a list which you could sort by the values you want and divide to how many groups you want.
from easygui import *
from operator import attrgetter
class Student(object):
def __init__(self, name, grade, athleticism, intellect, adherance):
self.name = name
self.grade = int(grade)
self.athleticism = int(athleticism)
self.intellect = int(intellect)
self.adherance = int(adherance)
self.total = self.athleticism + self.intellect + self.adherance
def __str__(self): # When converting an instance of this class to a string it'll return the string below.
return "Name: %s, Grade: %s, Athleticism (1-10): %s, Intellect (1-10): %s, Adherance to school rules (1-10): %s"\
% (self.name, self.grade, self.athleticism, self.intellect, self.adherance)
student_group = []
while ynbox("Would you like to enter a student?"): # Returns 'True' or 'False' so it'll loop every time the user press 'yes'.
message = "Student's Information"
title = "House Sorting Program"
field_names = ["Name", "Grade", "Athleticism (1-10)", "Intellect (1-10)", "Adherance to school rules (1-10)"]
field_values = multenterbox(message, title, field_names)
student = Student(*field_values) # Unpack all elements in the list 'field_values' to the initializer.
student_group.append(student) # Add the student to the group 'student_group'.
# When the user has put in all the students we sort our group by 'total' (or any other value you want to sort by).
sorted_group = sorted(student_group, key=attrgetter("total"), reverse=True)
# Just as an example I divided the students into 3 groups based on their total.
best_students = sorted_group[:len(sorted_group) // 3]
average_students = sorted_group[len(sorted_group) // 3:2 * len(sorted_group) // 3]
worst_students = sorted_group[2 * len(sorted_group) // 3::]

Python Dynamic Object Creation [duplicate]

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)

How do I assign a variable to an object name?

Tried the following, where "objectname" contains a string name, to be assigned on creation of an object.
for record in result:
objectname = 'Customer' + str(record[0])
print objectname
customername = str(record[1])
objectname = Customer(customername)
Where Customer is a class.
In my test, this loop runs twice printing "objectname" as Customer1 and Customer2, yet creates 2 objects, but the objects are called "objectname" (it overwrites each loop), opposed to the 2 unique objects Customer1 or Customer2.
Its simply not assigning strings(customer1,2) inside the variable, but purely the variables name.
I've tried assigning strings to the object name, but that gives a syntax error
Surely this must be done all the time, thanks for your help in advance.
Instead of using a new variable for each customer you could store your object in a Python dictionary:
d = dict()
for record in result:
objectname = 'Customer' + str(record[0])
customername = str(record[1])
d[objectname] = Customer(customername)
print d
An example of objects stored in dictionaries
I just could'nt help my self writting some code (more than I set out to do). It's like addictive. Anyway, I would'nt use objects for this kind of work. I probably would use a sqlite database (could be saved in memory if you want). But this piece of code show you (hopefully) how you can use dictionaries to save objects with customer data in:
# Initiate customer dictionary
customers = dict()
class Customer:
def __init__(self, fname, lname):
self.fname = fname
self.lname = lname
self.address = None
self.zip = None
self.state = None
self.city = None
self.phone = None
def add_address(self, address, zp, state, city):
self.address = address
self.zip = zp
self.state = state
self.city = city
def add_phone(self, number):
self.phone = number
# Observe that these functions are not belonging to the class.
def _print_layout(object):
print object.fname, object.lname
print '==========================='
print 'ADDRESS:'
print object.address
print object.zip
print object.state
print object.city
print '\nPHONE:'
print object.phone
print '\n'
def print_customer(customer_name):
_print_layout(customers[customer_name])
def print_customers():
for customer_name in customers.iterkeys():
_print_layout(customers[customer_name])
if __name__ == '__main__':
# Add some customers to dictionary:
customers['Steve'] = Customer('Steve', 'Jobs')
customers['Niclas'] = Customer('Niclas', 'Nilsson')
# Add some more data
customers['Niclas'].add_address('Some road', '12312', 'WeDon\'tHaveStates', 'Hultsfred')
customers['Steve'].add_phone('123-543 234')
# Search one customer and print him
print 'Here are one customer searched:'
print 'ooooooooooooooooooooooooooooooo'
print_customer('Niclas')
# Print all the customers nicely
print '\n\nHere are all customers'
print 'oooooooooooooooooooooo'
print_customers()
It is generally not that useful to have dynamically generated variable names. I would definitely suggest something like Niclas' answer instead, but if you know this is what you want here is how you can do it:
for record in result:
objectname = 'Customer' + str(record[0])
print objectname
customername = str(record[1])
exec '%s = Customer(%r)' % (customername, customername)
This will result in the variables Customer1 and Customer2 being added to the innermost scope, exactly like if you had executed the following lines:
Customer1 = Customer('Customer1')
Customer2 = Customer('Customer2')
When doing it this way you need to make sure that customername is a valid Python identifier.
What you need is a dictionary:
customers = {}
for record in result:
objectname = 'Customer' + str(record[0])
customers[customername] = Customer(str(record[1])) #assignment to dictionary

Categories