Problem retrieving individual objects in pickled dictionary (Python 3) - python-3.x

My program stores "food" objects that are pickled into a dictionary and stored in a csv file, which acts as a database. I want to retrieve individual food objects on command from the dictionary, but when I attempt to I seem to only retrieve the last object in the dictionary.
import pickle
class Food(object):
fooddict = dict({})
def __init__(self, name, weight, calories, time):
self.name = name
self.weight = weight
self.calories = calories
self.time = time
def __str__(self):
return '{self.name}s'.format(self=self) + \
' weigh {self.weight}'.format(self=self) + \
' ounces, contain {self.calories}'.format(self=self) + \
' calories, and stay fresh for {self.time}'.format(self=self) + \
' days.'
#classmethod
def createFoodInput(cls):
name = str(input("Enter the name: "))
weight = float(input("Enter the weight: "))
calories = float(input("Enter the calories: "))
time = float(input("Enter how many days it can store for: "))
return cls(name, weight, calories, time)
def storeFoodDict(f):
fooddict = Food.retreiveFoodDict()
if fooddict == "Empty File":
fooddict = dict({f.name: f})
with open("food.csv", 'wb') as filewriter:
try:
pickle.dump(fooddict, filewriter)
except:
print("Error storing pickled dictionary")
else:
food_found = False
for key in list(fooddict):
if key.__eq__(f.name):
print("Food already stored!")
food_found = True
if not food_found:
fooddict.update({f.name: f})
with open("food.csv", 'wb') as filewriter:
try:
pickle.dump(fooddict, filewriter)
except:
print("Error storing pickled dictionary")
#classmethod
def retreiveFoodDict(cls):
with open("food.csv", 'rb') as filereader:
try:
fooddict = pickle.load(filereader)
return fooddict
except EOFError:
return("Empty File")
def findFood(title):
fooddict = Food.retreiveFoodDict()
for key in list(fooddict):
if key.__eq__(title):
continue
return fooddict[key]
s = "apple"
n = findFood(s) #does not work, it returns banana instead of apple
#which is really just grabbing whatever is the
#last object in the dictionary
m = findFood("banana") #seems to work, but only because banana is the
#last object in the dictionary
print(n) #should print an apple "food object" but instead prints a banana
print(str(m.calories)) #works, but if I said n.calories it would still print
#m.calories instead
p = Food.retreiveFoodDict() #seems to work and retrieve the dictionary
print(str(p)) #also seems to work of course
Console Output:
bananas weigh 5.0 ounces, contain 120.0 calories, and stay fresh for 3.0 days.
120.0
{'apple': <main.Food object at 0x00D2C2E0>, 'banana': <main.Food object at 0x00D36D00>}
The dictionary contains 2 food objects (apple and banana), but the print(n) statement shows a banana, not an apple. Can anyone point out why this is or what I am misunderstanding? Thank you so much!

I found the answer to my own problem. I was misusing the continue in my findFood function.
This code solved my issues.
def getFood(food_name):
fooddict = Food.retreiveFoodDict()
for key in list(fooddict):
if key.__eq__(food_name):
return fooddict[key]
What this function does is simply retrieve a dictionary of objects in a csv file and iterates through the keys until the passed key name is located. If found, the proper key name will be returned as a food object. My original mistake was using the "continue" keyword to stop the for-loop, which was returning the object directly after the one we wanted.

Related

AttributeError Problem with Multiple inheritance in python

I wanted to calculate the Total and Average Marks of a student with multiple inheritances in python. But whenever I create an object for my child class it gives me access to all the methods of parent classes but shows an AttributeError when I call the method of the child class. I tried to use the super() function but the result is the same.
I just paste my code below. Can you suggest to me a solution to that?
class Student_Marks:
def __init__(self):
# initializing variables
self.__roll: int
self.__marks1: int
self.__marks2: int
def getMarks(self):
self.__roll = int(input("Enter Roll No: "))
self.__marks1, self.__marks2 = map(int, input("Enter Marks: ").split())
return self.__roll, self.__marks1, self.__marks2
class Cocurricular_Marks:
def __init__(self):
self.__activemarks: int
def getActiveMarks(self):
self.__activemarks = int(input("Enter Co Curricular Activities Marks: "))
return self.__activemarks
class Result(Student_Marks, Cocurricular_Marks):
def __init__(self):
super().getMarks()
super().getActiveMarks()
def display(self):
total = self.__marks1 + self.__marks2 + self.__activemarks
avg = total / 3
print("Roll No: ", self.__roll)
print("Total Marks: ", total)
print("Average Marks: ", avg )
# creating Objects
res = Result()
res.getMarks()
res.getActiveMarks()
res.display() # I got problem here
You're prepending the attributes with two underscores in the classes, this mangles the name of the attribute (see the documentation on Private Variables).
For instance, Student_Marks's __roll will be mangled to _Student_Marks__roll as you exit getMarks.
Hence Result.display() not being able to access self.__marks1, but it can access it as self._Student_Marks__marks1.
See the following minimal example.
class K:
__a = 1
class KK(K):
pass
k = K()
k.__a # AttributeError: 'K' object has no attribute '__a'
k._K__a # 1
kk = KK()
kk._K__a # 1

Data Structure Option

I'm wondering what appropriate data structure I'm going to use to store information about chemical elements that I have in a text file. My program should
read and process input from the user. If the user enters an integer then it program
should display the symbol and name of the element with the number of protons
entered. If the user enters a string then my program should display the number
of protons for the element with that name or symbol.
The text file is formatted as below
# element.txt
1,H,Hydrogen
2,He,Helium
3,Li,Lithium
4,Be,Beryllium
...
I thought of dictionary but figured that mapping a string to a list can be tricky as my program would respond based on whether the user provides an integer or a string.
You shouldn't be worried about the "performance" of looking for an element:
There are no more than 200 elements, which is a small number for a computer;
Since the program interacts with a human user, the human will be orders of magnitude slower than the computer anyway.
Option 1: pandas.DataFrame
Hence I suggest a simple pandas DataFrame:
import pandas as pd
df = pd.read_csv('element.txt')
df.columns = ['Number', 'Symbol', 'Name']
def get_column_and_key(s):
s = s.strip()
try:
k = int(s)
return 'Number', k
except ValueError:
if len(s) <= 2:
return 'Symbol', s
else:
return 'Name', s
def find_element(s):
column, key = get_column_and_key(s)
return df[df[column] == key]
def play():
keep_going = True
while keep_going:
s = input('>>>> ')
if s[0] == 'q':
keep_going = False
else:
print(find_element(s))
if __name__ == '__main__':
play()
See also:
Finding elements in a pandas dataframe
Option 2: three redundant dicts
One of python's most used data structures is dict. Here we have three different possible keys, so we'll use three dict.
import csv
with open('element.txt', 'r') as f:
data = csv.reader(f)
elements_by_num = {}
elements_by_symbol = {}
elements_by_name = {}
for row in data:
num, symbol, name = int(row[0]), row[1], row[2]
elements_by_num[num] = num, symbol, name
elements_by_symbol[symbol] = num, symbol, name
elements_by_name[name] = num, symbol, name
def get_dict_and_key(s):
s = s.strip()
try:
k = int(s)
return elements_by_num, k
except ValueError:
if len(s) <= 2:
return elements_by_symbol, s
else:
return elements_by_name, s
def find_element(s):
d, key = get_dict_and_key(s)
return d[key]
def play():
keep_going = True
while keep_going:
s = input('>>>> ')
if s[0] == 'q':
keep_going = False
else:
print(find_element(s))
if __name__ == '__main__':
play()
You are right that it is tricky. However, I suggest you just make three dictionaries. You certainly can just store the data in a 2d list, but that'd be way harder to make and access than using three dicts. If you desire, you can join the three dicts into one. I personally wouldn't, but the final choice is always up to you.
weight = {1: ("H", "Hydrogen"), 2: ...}
symbol = {"H": (1, "Hydrogen"), "He": ...}
name = {"Hydrogen": (1, "H"), "Helium": ...}
If you want to get into databases and some QLs, I suggest looking into sqlite3. It's a classic, thus it's well documented.

Trouble with reading a dictionary file

Hi my assignment is to read the company names and the shorten names of the companies.
This file with tickers below is given:
ticker_symbol.txt
YAHOO:YHOO
GOOGLE INC:GOOG
Harley-Davidson:HOG
Yamana Gold:AUY
Sotheby's:BID
inBev:BUD
So I need to make 3 functions: def tickers_to_dict(filename), def name_to_symbol(name, ticker_dict) and def symbol_to_name(symbol, ticker_dict).
In the function tickers_to_dict(filename), I need to convert the text file into a dictionary and return it which I have done succesfully.
In the functions def name_to_symbol(name, ticker_dict) and def symbol_to_name(symbol, ticker_dict), I need to find the ticker symbol in the dictionary by the input of the company name and the reverse. (by a input of a ticker symbol it needs to find the company name). But I dont know how to solve this two functions. Can someone help me? So far I have this:
def tickers_to_dict():
ticker_dict = {}
bestand = open('ticker_symbol.txt', 'r')
tickers = bestand.readlines()
for line in tickers:
k, v = line.split(':')
ticker_dict[k] = v
return (ticker_dict)
print(tickers_to_dict())
def name_to_symbol(name, ticker_dict):
output needs to be like this:
Enter Company name: YAHOO
Ticker symbol: YHOO
Enter Ticker symbol: BUD
Company name: inBev
I am not sure this ist what you were looking for but here you go:
def name_to_symbol(mydict):
given_input = input("Enter company name: ")
try:
print("Ticker symbol: ", mydict[given_input])
except:
print("False Input")
def symbol_to_name(mydict):
given_input = input("Enter ticker: ")
for key, value in mydict.items():
if given_input == value:
print("Company name: ", key)
return
print("False Input")
I hope this helped you out. If you want to know how it exactly works, you can let me know.
Also this search is case sensitiv. In the textfile you have quite a mess of uppercase and lowercase. Maybe address that if you want to simplify the use of your programm a bit.
def tickers_to_dict():
ticker_dict = {}
bestand = open('pe_8_4_tickers.txt', 'r')
tickers = bestand.readlines()
for line in tickers:
k, v = line.split(':')
ticker_dict[k] = v
return (ticker_dict)
def name_to_symbol(mydict):
given_input = input("Enter company name: ")
for key, value in mydict.items():
if given_input == key:
print("Ticker symbol:", value)
return
else:
# print("Ticker symbol: )
# except:
print("False Input")
def symbol_to_name(mydict):
given_input = input("Enter ticker symbol: ")
for key, value in mydict.items():
if given_input == value:
print("Ticker symbol:", key)
return
else:
print("False Input")
name_to_symbol(tickers_to_dict())
symbol_to_name(tickers_to_dict())
Athos it didnt work
second def statement returns with false input

Can't change instance attribute of my class?

I'm starting out in python and I can't quite figure out why I'm unable to change the data stored in one of my instance attributes. I have the following code:
class Bank:
def __init__(self, bank = 'Unnamed'):
self.bank = bank
self.clients = []
self.status = {'bank': self.bank, 'clients': self.clients}
self.c_counter=0
def deposit(self, name = None, amount = 200):
self.name = name
self.amount = amount
self.c_counter += 1
if self.name is None:
self.name = print("client" + str(self.c_counter));
self.clients.append((self.name, self.amount))
else:
self.clients.append((self.name, self.amount))
This produces the following output:
bb = Bank("bb")
bb.deposit(amount = 2000)
bb.status
out: {'bank': bb, 'clients': [(None, 2000)]}
While the desired output is:
out: {'bank': bb, 'clients': [('client1', 2000)]}
As you can see, what I'm trying to do is to set the client name to "clientx" if client name is not specified during a deposit; the x is just a number to distinguish each generic client from other generic clients without a specific name.
If a specific name is not provided when calling the deposit attribute of the bank the client name is set to None by default. I check this with the if condition and change the client name accordingly, but for some reason the client name literally gets added as "None" to the list of clients in the dictionary (list of tuples). What is wrong here?
print prints a string to sys.stdout and returns None. you should change the line
self.name = print("client" + str(self.c_counter));
to
self.name = "client" + str(self.c_counter)
or maybe self.name = f"client{self.c_counter}" for python >= 3.6.
print is a NoneType, it's None and you can prove it:
>>> type(print())
<class 'NoneType'>
>>>
And:
>>> print(print())
None
>>>
So print isn't be used for assigning, print is used for outputting stuff, whereas in this case you're assigning stuff, that which isn't meant for print to handle, so change:
self.name = print("client" + str(self.c_counter));
To:
self.name = "client" + str(self.c_counter)
Or:
self.name = "client%s" % self.c_counter
Or:
self.name = "client{}".format(self.c_counter)
Or if your python version is bigger or equal to 3.6, you can use:
self.name = f"client{self.c_counter}"

pd.rename key KeyError: 'New_Name'

Edit 12/07/19: The problem was not in fact with pd.rename fuction but the fact that I did not return from the function the pandas dataframe and as a result the column change did not exist when printing. i.e.
def change_column_names(as_pandas, old_name, new_name):
as_pandas.rename(columns={old_name: new_name}, inplace=)
return as_pandas <- This was missing*
Please see the user comment below to uptick them for finding this error for me.
Alternatively, you can continue reading.
The data can be downloaded from this link, yet I have added a sample dataset. The formatting of the file is not a typical CSV file and I believe this may have been an assessment piece and is related to Hidden Decision Tree article. I have given the portion of the code as it solves the issues surrounding the format of the text file as mentioned above and allows the user to rename the column.
The problem occured when I tried to assign create a re-naming function:
def change_column_names(as_pandas, old_name, new_name):
as_pandas.rename(columns={old_name: new_name}, inplace=)
However, it seem to work when I set the variable names inside rename function.
def change_column_names(as_pandas):
as_pandas.rename(columns={'Unique Pageviews': 'Page_Views'}, inplace=True)
return as_pandas
Sample Dataset
Title URL Date Unique Pageviews
oupUrl=tutorials 18-Apr-15 5608
"An Exclusive Interview with Data Expert, John Bottega" http://www.datasciencecentral.com/forum/topics/an-exclusive-interview-with-data-expert-john-bottega?groupUrl=announcements 10-Jun-14 360
Announcing Composable Analytics http://www.datasciencecentral.com/forum/topics/announcing-composable-analytics 15-Jun-14 367
Announcing the release of Spark 1.5 http://www.datasciencecentral.com/forum/topics/announcing-the-release-of-spark-1-5 12-Sep-15 156
Are Extreme Weather Events More Frequent? The Data Science Answer http://www.datasciencecentral.com/forum/topics/are-extreme-weather-events-more-frequent-the-data-science-answer 5-Oct-15 204
Are you interested in joining the University of California for an empiricalstudy on 'Big Data'? http://www.datasciencecentral.com/forum/topics/are-you-interested-in-joining-the-university-of-california-for-an 7-Feb-13 204
Are you smart enough to work at Google? http://www.datasciencecentral.com/forum/topics/are-you-smart-enough-to-work-at-google 11-Oct-15 3625
"As a software engineer, what's the best skill set to have for the next 5-10years?" http://www.datasciencecentral.com/forum/topics/as-a-software-engineer-what-s-the-best-skill-set-to-have-for-the- 12-Feb-16 2815
A Statistician's View on Big Data and Data Science (Updated) http://www.datasciencecentral.com/forum/topics/a-statistician-s-view-on-big-data-and-data-science-updated-1 21-May-14 163
A synthetic variance designed for Hadoop and big data http://www.datasciencecentral.com/forum/topics/a-synthetic-variance-designed-for-hadoop-and-big-data?groupUrl=research 26-May-14 575
A Tough Calculus Question http://www.datasciencecentral.com/forum/topics/a-tough-calculus-question 10-Feb-16 937
Attribution Modeling: Key Analytical Strategy to Boost Marketing ROI http://www.datasciencecentral.com/forum/topics/attribution-modeling-key-concept 24-Oct-15 937
Audience expansion http://www.datasciencecentral.com/forum/topics/audience-expansion 6-May-13 223
Automatic use of insights http://www.datasciencecentral.com/forum/topics/automatic-use-of-insights 27-Aug-15 122
Average length of dissertations by higher education discipline. http://www.datasciencecentral.com/forum/topics/average-length-of-dissertations-by-higher-education-discipline 4-Jun-15 1303
This is the full code that produces the Key Error:
def change_column_names(as_pandas):
as_pandas.rename(columns={'Unique Pageviews': 'Page_Views'}, inplace=True)
def change_column_names(as_pandas, old_name, new_name):
as_pandas.rename(columns={old_name: new_name}, inplace=True)
def change_column_names(as_pandas):
as_pandas.rename(columns={'Unique Pageviews': 'Page_Views'},
inplace=True)
def open_as_dataframe(file_name_in):
reader = pd.read_csv(file_name_in, encoding='windows-1251')
return reader
# Get each column of data including the heading and separate each element
i.e. Title, URL, Date, Page Views
# and save to string_of_rows with comma separator for storage as a csv
# file.
def get_columns_of_data(*args):
# Function that accept variable length arguments
string_of_rows = str()
num_cols = len(args)
try:
if num_cols > 0:
for number, element in enumerate(args):
if number == (num_cols - 1):
string_of_rows = string_of_rows + element + '\n'
else:
string_of_rows = string_of_rows + element + ','
except UnboundLocalError:
print('Empty file \'or\' No arguments received, cannot be zero')
return string_of_rows
def open_file(file_name):
try:
with open(file_name) as csv_file_in, open('HDT_data5.txt', 'w') as csv_file_out:
csv_read = csv.reader(csv_file_in, delimiter='\t')
for row in csv_read:
try:
row[0] = row[0].replace(',', '')
csv_file_out.write(get_columns_of_data(*row))
except TypeError:
continue
print("The file name '{}' was successfully opened and read".format(file_name))
except IOError:
print('File not found \'OR\' Not in current directory\n')
# All acronyms used in variable naming correspond to the function at time
# of return from function.
# csv_list being a list of the v file contents the remainder i.e. 'st' of
# csv_list_st = split_title().
def main():
open_file('HDTdata3.txt')
multi_sets = open_as_dataframe('HDT_data5.txt')
# change_column_names(multi_sets)
change_column_names(multi_set, 'Old_Name', 'New_Name')
print(multi_sets)
main()
I cleaned up your code so it would run. You were changing the column names but not returning the result. Try the following:
import pandas as pd
import numpy as np
import math
def set_new_columns(as_pandas):
titles_list = ['Year > 2014', 'Forum', 'Blog', 'Python', 'R',
'Machine_Learning', 'Data_Science', 'Data',
'Analytics']
for number, word in enumerate(titles_list):
as_pandas.insert(len(as_pandas.columns), titles_list[number], 0)
def title_length(as_pandas):
# Insert new column header then count the number of letters in 'Title'
as_pandas.insert(len(as_pandas.columns), 'Title_Length', 0)
as_pandas['Title_Length'] = as_pandas['Title'].map(str).apply(len)
# Although it is log, percentage of change is inverse linear comparison of
#logX1 - logX2
# therefore you could think of it as the percentage change in Page Views
# map
# function allows for function to be performed on all rows in column
# 'Page_Views'.
def log_page_view(as_pandas):
# Insert new column header
as_pandas.insert(len(as_pandas.columns), 'Log_Page_Views', 0)
as_pandas['Log_Page_Views'] = as_pandas['Page_Views'].map(lambda x: math.log(1 + float(x)))
def change_to_numeric(as_pandas):
# Check for missing values then convert the column to numeric.
as_pandas = as_pandas.replace(r'^\s*$', np.nan, regex=True)
as_pandas['Page_Views'] = pd.to_numeric(as_pandas['Page_Views'],
errors='coerce')
def change_column_names(as_pandas):
as_pandas.rename(columns={'Unique Pageviews': 'Page_Views'}, inplace=True)
return as_pandas
def open_as_dataframe(file_name_in):
reader = pd.read_csv(file_name_in, encoding='windows-1251')
return reader
# Get each column of data including the heading and separate each element
# i.e. Title, URL, Date, Page Views
# and save to string_of_rows with comma separator for storage as a csv
# file.
def get_columns_of_data(*args):
# Function that accept variable length arguments
string_of_rows = str()
num_cols = len(args)
try:
if num_cols > 0:
for number, element in enumerate(args):
if number == (num_cols - 1):
string_of_rows = string_of_rows + element + '\n'
else:
string_of_rows = string_of_rows + element + ','
except UnboundLocalError:
print('Empty file \'or\' No arguments received, cannot be zero')
return string_of_rows
def open_file(file_name):
import csv
try:
with open(file_name) as csv_file_in, open('HDT_data5.txt', 'w') as csv_file_out:
csv_read = csv.reader(csv_file_in, delimiter='\t')
for row in csv_read:
try:
row[0] = row[0].replace(',', '')
csv_file_out.write(get_columns_of_data(*row))
except TypeError:
continue
print("The file name '{}' was successfully opened and read".format(file_name))
except IOError:
print('File not found \'OR\' Not in current directory\n')
# All acronyms used in variable naming correspond to the function at time
# of return from function.
# csv_list being a list of the v file contents the remainder i.e. 'st' of
# csv_list_st = split_title().
def main():
open_file('HDTdata3.txt')
multi_sets = open_as_dataframe('HDT_data5.txt')
multi_sets = change_column_names(multi_sets)
change_to_numeric(multi_sets)
log_page_view(multi_sets)
title_length(multi_sets)
set_new_columns(multi_sets)
print(multi_sets)
main()

Resources