having trouble writing dictionary list as a string - python

I'm trying to write a program that creates an address book with contact names, emails, phone numbers, etc. I store each contact as a dictionary and then place each person (dictionary) into a global list. I then convert the list to a string using repr() and write it to a file. When I try to reload the list and write what it contains, I get a list of empty dictionaries. Please help me figure out what is wrong.
Here is my code:
list = []
listfile = 'phonebook.txt'
class bookEntry(dict):
total = 0
def __init__(self):
bookEntry.total += 1
self.d = {}
def __del__(self):
bookEntry.total -= 1
class Person(bookEntry):
def __init__(self, n):
bookEntry.__init__(self)
self.n = n
print '%s has been created' % (self.n)
def addnewperson(self, n, e = '', ph = '', note = ''):
f = file(listfile, 'w')
self.d['name'] = n
self.d['email'] = e
self.d['phone'] = ph
self.d['note'] = note
list.append(self)
listStr = repr(list)
f.write(listStr)
f.close()
I start the program with a startup() function:
def startup():
aor = raw_input('Hello! Would you like to add an entry or retrieve one?')
if aor == 'add':
info = raw_input('Would you like to add a person or a company?')
if info == 'person':
n = raw_input('Please enter this persons name:')
e = raw_input('Please enter this persons email address:')
ph = raw_input('Please enter this persons phone number:')
note = raw_input('Please add any notes if applicable:')
X = Person(n)
X.addnewperson(n, e, ph, note)
startup()
I add these answers to the prompts:
'''
Hello! Would you like to add an entry or retrieve one?add
Would you like to add a person or a company?person
Please enter this persons name:Pig
Please enter this persons email address:pig#brickhouse.com
Please enter this persons phone number:333-333-3333
Please add any notes if applicable:one of three
Pig has been created
'''
When I open phonebook.txt, this is what I see:
[{}]
Why are empty dictionaries being returned?

You're deriving from dict, but storing all the elements in a member d. Hence, repr gives you a string representing an empty dict. If you want to use a bookEntry as a dict, insert the info with
self['name'] = n
instead of
self.d['name'] = n
(But really, you shouldn't be inheriting from dict here. Also, please don't use list as an identifier, it's the name of a builtin.)

you should save self.d instead of self:
alist.append(self.d)
listStr = repr(alist)
f.write(listStr)
btw don't use list as the name of a variable, you are overwritting the keyword list

Your problem is that the X.d dictionary is not the same as the dictionary "bookEntry" is inheriting from. Therefore repr(X) is not showing X.d
A solution might be to override repr in BookEntry:
e.g.
def __repr___(self):
return repr(self.d)

Related

This for loop displays only the last entry of the student record

when I create a number of instances in the student class
the display method only displays the last entry
here is my code
class student:
def __init__(self):
self.usn= None
self.name=None
self.branch=None
self.phno=None
def read(self):
self.usn=input("enter the usn: ")
self.name=input("enter the name: ")
self.branch=input("enter the branch: ")
self.phno=input("enter the phno: ")
def display(self):
print(f'\n{self.usn} {self.name} {self.branch} {self.phno}\n')
print(f'\nusn %name branch phno\n')
n=int(input("enter number of students : "))
for i in range(n):
emp=student()
emp.read()
print("\nusn name branch phno\n")
for i in student():
emp[i].display()
The read method works well,I am able to enter many student records
but I have an issue with the display method which only prints the last student record
so I tried to iterate the loop but ended up with an error
for i in student():
emp[i].display()
TypeError: 'int' object is not iterable
so how do I iterate to retrieve all the objects
and get to display all the entered student records
You are using the same variable inside the for loop. on each iteration the last entered student get deleted and replaced with the new data. You should use an array (or any other suitable data structure for your use case) and add a new Student in the array on every iteration.
this code should work:
arr = list()
for i in range(n):
emp=student()
emp.read()
arr.append(emp)
You need a structure to hold all the objects of your class, for example, a list.
An empty list can be simply created with emp = [].
Then you can append your objects to the list with the method append().
So you have:
emp = [] #declare empty list
for i in range(n):
emp.append(student())
emp[i].read()
Then you can iterate directly over the list:
for x in emp:
x.display()
On each iteration, x will be the next object in the list
With the answers given by other users,I got the right output I wanted
Here is the code
class student:
def __init__(self):
self.usn= None
self.name=None
self.branch=None
self.phno=None
def read(self):
self.usn=input("enter the usn: ")
self.name=input("enter the name: ")
self.branch=input("enter the branch: ")
self.phno=input("enter the phno: ")
def display(self):
print(f'\n{self.usn} {self.name} {self.branch} {self.phno}\n')
n=int(input("enter number of students : "))
arr = list()
for i in range(n):
emp=student()
emp.read()
arr.append(emp)
for x in arr:
x.display()

I am looking to create instances of a class from user input

I Have this class:
class Bowler:
def __init__(self, name, score):
self.name = name
self.score = score
def nameScore(self):
return '{} {}'.format(self.name, self.score)
I need to get user input until a blank line is entered. Then use the data I got to create instances of a class. I was thinking something like:
def getData():
name, score = input("Please enter your credentails (Name score): ").split()
B1 = Bowler(name, score)
print(B1.nameScore())
But then I would somehow have to loop it until I get a blank user input. Also I would somehow have to create B2 B3 B4 etc in the loop.
Sorry I am still really new to programming, maybe I am looking at this from the wrong angle.
What you're looking for are Python Lists. With these you will be able to keep track of your newly created items while running the loop. To create a list we simply defined it like so:
our_bowlers = []
Now we need to alter our getData function to return either None or a new Bowler:
def getData():
# Get the input
our_input = input("Please enter your credentails (Name score): ").split()
# Check if it is empty
if our_input == '':
return None
# Otherwise, we split our data and create the Bowler
name, score = our_input.split()
return Bowler(name, score)
and then we can run a loop, check for a new Bowler and if we didn't get anything, we can print all the Bowlers we created:
# Get the first line and try create a Bowler
bowler = getData()
# We loop until we don't have a valid Bowler
while bowler is not None:
# Add the Bowler to our list and then try get the next one
our_bowlers.append(bowler)
bowler = getData()
# Print out all the collected Bowlers
for b in our_bowlers:
print(b.nameScore())
This is my code to do what you want:
class Bowler:
def __init__(self, name, score):
self.name = name
self.score = score
def nameScore(self):
return '{} {}'.format(self.name, self.score)
def getData():
try:
line = input("Please enter your credentails (Name score): ")
except SyntaxError as e:
return None
name, score = line.split()
score = int(score)
B = Bowler(name, score)
print(B.nameScore())
return B
if __name__ == '__main__':
bowlers = list()
while True:
B = getData()
if B == None:
break
bowlers.append(B)
for B in bowlers:
print(B.nameScore())
In addition, I recommend you to modify your input for it's inconvenient now

Nested List Comparison

Python noob here so please bear with me! I have a list that looks like this:
bookList = [("Wuthering Heights", "fred"), ("Everville", "fred"), ("Wuthering Heights", "dan")]
What I’m trying to do is write a function that looks at each nested list and sees who shares books in common with who, depending who is logged in. For example, if dan was logged in, the system would say “fred also has plums”.
I have a dictionary set up the holds usernames as keys and passwords as their value.
I’m kind of struggling with list comprehension when they involve anything nested, and help would be greatly appreciated!
I don't think your existing data structure is really ideal for this. What I would do would be to pre-process it into a dictionary whose keys are the usernames and the values are sets of books. Then you can do a loop or list comprehension to compare the logged-in user with all the other users and see if there is anything in common. So:
from collections import defaultdict
bookdict = defaultdict(set)
for book, name in bookList:
bookdict[name].add(book)
logged_in_user = 'fred'
for person, books in bookdict.items():
if person == logged_in_user:
continue
common = books.intersection(bookdict[logged_in_user])
if common:
print '%s also has %s' % (person, ', '.join(common))
def common_books(user):
user_books = {b for b, u in bookList if u == user}
for b, u in bookList:
if b in user_books and u != user:
print '{0} also has {1}'.format(u,b)
If you're trying to get the books that fred has in the list
filter(lambda x: x[1] == "fred", bookList)
Another version as per Bakuriu's comment.
class Session:
def __init__(self):
self.books = ["Wuthering Heights", "Everville"]
self.username = "fred"
bookList = [("Wuthering Heights", "fred"), ("Everville", "fred"), ("Wuthering Heights", "dan")]
if __name__ == "__main__":
session = Session()
for book in bookList:
if book[1] != session.username and book[0] in session.books:
print "{} also has {}".format(book[1], book[0])

Global Name Not Defined in Python

Am new to Python OOP. Please dont be harsh. Here is my code which calculates which is the fastest time of an athlete from a list and displays them. But When Running, I get this error:
z= add.mylist.min()
NameError: global name 'add' is not defined
My Code:
class Athlete:
def add(self):
list=[]
mylist=[]
for i in range(2):
self.name = raw_input("Enter name: ")
self.fastest_time = input("time: ")
list.append(self.name)
mylist.append(self.fastest_time)
print "Names: ",list
print "Fastest times: ",mylist
def display(self):
z= add.mylist.min()
w= add.mylist.index(z)
print "Minimum time: ",z
print "Name of athelte with fastest time: ",list[w]
x = Athlete()
x.add()
x.display()
You need to refer to methods on the instance with the self parameter. In addition, your add() method needs to return the mylist variable it generates, you cannot refer to method local variables as attributes on methods:
def display(self):
mylist = self.add()
z = min(mylist)
w = mylist.index(z)
def add(self):
list=[]
mylist=[]
for i in range(2):
self.name = raw_input("Enter name: ")
self.fastest_time = input("time: ")
list.append(self.name)
mylist.append(self.fastest_time)
print "Names: ",list
print "Fastest times: ",mylist
return mylist
That is what self is for, as a reference point to find instance attributes and other methods on the same object.
You may want to rename list to something that does not shadow the built-in type.
Martijn has already answered your question, so here are some remarks and code style tips:
New-style classes derive from object
You have both athlete names and their times, those belong together as key-value pairs in a dictionary instead of two separate lists
Don't use print statements inside class methods, a class method should return an object that you then can print
what if you have more then 2 athletes for which you want to enter the time? If you make the number of athletes an argument of your function, you can add a variable number of athlethes
give descriptive variable names (not mylist) and don't use names of builtin functions (like list) as variable name
variables that you want to use throughout your class can be initalized in an __init__method.
For printing, use the format function instead of using commas
use if __name__ == '__main__' so that your Python file can act as either reusable modules or as standalone program
Taking these into account, I would rewrite your code to something like this:
from collections import defaultdict
class Athlete(object): # see (1)
def __init__(self): # see (6)
self.athlete_times = defaultdict(str) # see (2)
def add_athletes_and_times(self, n): # see (4)
for i in range(n):
self.name = raw_input("Enter name: ")
self.fastest_time = input("time (in seconds): ")
self.athlete_times[self.fastest_time] = self.name
def get_fastest_time(self):
return min(self.athlete_times) # see (3)
if __name__ == '__main__': # see (8)
x = Athlete()
x.add_athletes_and_times(2)
for fast_time in x.athlete_times:
print "The fastest time of athlete {0} is {1} seconds.".format(
x.athlete_times[fast_time], fast_time) # see (7)
fastest_time = x.get_fastest_time()
print "The overall fastest time is: {0} seconds for athlete {1}.".format(
fastest_time, x.athlete_times[fastest_time])

Class deletion in cmd but not in IDLE

When I run this code in the command prompt, the Person I create is automatically deleted, but when in IDLE the deletion does not occur. Why?
NOTE: This is a program that is supposed to create an address book (a list of dictionaries)
Here is my code:
list = []
class bookEntry(dict):
total = 0
def __init__(self):
bookEntry.total += 1
self.d = {}
def __del__(self):
bookEntry.total -= 1
list.remove(self)
class Person(bookEntry):
def __init__(self, n):
bookEntry.__init__(self)
self.n = n
print '%s has been created' % (self.n)
def __del__(self):
print '%s has been deleted' % (self.n)
def addnewperson(self, n, e = '', ph = '', note = ''):
self.d['name'] = n
self.d['email'] = e
self.d['phone'] = ph
self.d['note'] = note
list.append(self)
I run the code with a startup function:
def startup():
aor = raw_input('Hello! Would you like to add an entry or retrieve one?')
if aor == 'add':
info = raw_input('Would you like to add a person or a company?')
if info == 'person':
n = raw_input('Please enter this persons name:')
e = raw_input('Please enter this persons email address:')
ph = raw_input('Please enter this persons phone number:')
note = raw_input('Please add any notes if applicable:')
X = Person(n)
X.addnewperson(n, e, ph, note)
startup()
When the code is run in IDLE I receive the following prompts, and submit the following answers:
'''
Hello! Would you like to add an entry or retrieve one?add
Would you like to add a person or a company?person
Please enter this persons name:Pig
Please enter this persons email address:pig#brickhouse.com
Please enter this persons phone number:333-333-3333
Please add any notes if applicable:one of three
Pig has been created
'''
Here, Pig is created and is not deleted. But in cmd.....
'''
Hello! Would you like to add an entry or retrieve one?add
Would you like to add a person or a company?person
Please enter this persons name:Pig
Please enter this persons email address:pig#brickhouse.com
Please enter this persons phone number:333-333-3333
Please add any notes if applicable:one of three
Pig has been created
Pig has been deleted
'''
Why is Pig being deleted?? __del__ is never called...
While you run in IDLE, the python process is still running even after you execute this program unless you exit from IDLE. But in command line, the python process executes your program and exits itself. So, that is where __del__ comes into play. When the reference count of the object is zero, it is automatically called to destroy it. so your object is deleted. When your program is ended and python process is itself terminated, there is no need for it to exist as well.
Reference
When the program ends, all variables are automatically deleted (otherwise, there would be a memory leak). IDLE keeps the environment open so you can keep using the variables you've created.
Note: My original answer was mistaken- I missed the lines
list = []
and
list.append(self)

Categories

Resources