Using Python 3 in Project 9 of Python For Kids For Dummies
In this post I talk about the changes that need to be made to the code of
Project 9 in order for it to work with Python 3. Most of the code in project 9 will work without changes.
However, in a lot of cases what Python outputs in Python 3 is different from the output in Python 2.7.
This project has a lot of code. To shorten the length of this post I am only showing the Python 3 versions of
the longer pieces, rather than both Python 2.7 (from the book) and Python 3.
Disclaimer
Some people want to use my book Python for Kids for Dummies to learn Python 3.
I am working through the code in the existing book, highlighting changes from Python 2 to Python 3
and providing code that will work in Python 3. If you are using Python 2.7 you can ignore this post.
This post is only for people who want to take the code in my book Python for Kids for Dummies and
run it in Python 3.
Page 240
All code on this page is the same, and all outputs from the code is the same in Python 3 as in Python 2.7.
However, in Python 3 you don’t need to add “(object)” when defining a class – it is assumed.
It is not an error to add (object) in Python 3, it just doesn’t look as nice. For example, on this page a class is defined
using class AddressEntry(object): (in Python 2.7). In Python 3 it’s just class AddressEntry:
>>> class AddressEntry(object): """ AddressEntry instances hold and manage details of a person """ pass >>> AddressEntry # without parentheses <class '__main__.AddressEntry'> >>> >>> AddressEntry() # parentheses create an instance <__main__.AddressEntry object at 0x7f9309751590> >>> address_entry = AddressEntry()
# Python 3 >>> class AddressEntry: # note: no (object) """ AddressEntry instances hold and manage details of a person """ pass >>> AddressEntry # without parentheses <class '__main__.AddressEntry'> >>> >>> AddressEntry() # parentheses create an instance <__main__.AddressEntry object at 0x7f9309751590> >>> address_entry = AddressEntry()
Page 241
All code on this page is the same, and all outputs from the code are the same in Python 3 as in Python 2.7.
Page 242
All code on this page is the same, and all outputs from the code is the same in Python 3 as in Python 2.7.
You still need to use () when creating instances of an object. That is, making an instance of a class, rather than
defining the class.
Page 244
All code on this page is the same, and all outputs from the code is the same in Python 3 as in Python 2.7
However, in Python 3 you don’t need to add “(object)” when defining a class – it is assumed.
It is not an error to add (object) in Python 3, it just doesn’t look as nice.
Python 2.7 """ Addressbook.py An address book program to store details of people I know. Stuff I'm storing is: first name family name email address date of birth [other stuff] Brendan Scott Feb 2015 """ ##### Classes Section class AddressBook(object): """ AddressBook instances hold and manage a list of people """ pass class AddressEntry(object): """ AddressEntry instances hold and manage details of a person """ ##### Main Section if __name__ == "__main__": address_book = AddressBook() person1 = AddressEntry()
# Python3 """ Addressbook.py An address book program to store details of people I know. Stuff I'm storing is: first name family name email address date of birth [other stuff] Brendan Scott Feb 2015 """ ##### Classes Section class AddressBook: """ AddressBook instances hold and manage a list of people """ pass class AddressEntry: """ AddressEntry instances hold and manage details of a person """ ##### Main Section if __name__ == "__main__": address_book = AddressBook() person1 = AddressEntry()
Page 245
All code on this page is the same, and all outputs from the code are the same in Python 3 as in Python 2.7.
Page 246
All code on this page is the same, and all outputs from the code is the same in Python 3 as in Python 2.7.
However, in Python 3 you don’t need to add “(object)” when defining a class – it is assumed.
It is not an error to add (object) in Python 3, it just doesn’t look as nice.
#Python2.7 class AddressEntry(object): """ AddressEntry instances hold and manage details of a person """ def __init__(self, first_name=None, family_name=None, email_address=None, date_of_birth=None): """Initialize attributes first_name, family_name and date_of_birth. Each argument should be a string. date_of_birth should be of the form "MM DD, YYYY" """ self.first_name = first_name self.family_name = family_name self.email_address = email_address self.date_of_birth = date_of_birth
#Python3 class AddressEntry: """ AddressEntry instances hold and manage details of a person """ def __init__(self, first_name=None, family_name=None, email_address=None, date_of_birth=None): """Initialize attributes first_name, family_name and date_of_birth. Each argument should be a string. date_of_birth should be of the form "MM DD, YYYY" """ self.first_name = first_name self.family_name = family_name self.email_address = email_address self.date_of_birth = date_of_birth
Page 248
All code on this page is the same, and all outputs from the code is the same in Python 3 as in Python 2.7.
However, in Python 3 you don’t need to add “(object)” when defining a class – it is assumed.
It is not an error to add (object) in Python 3, it just doesn’t look as nice.
############Python 2.7 ##### Classes Section class AddressBook(object): """ AddressBook instances hold and manage a list of people """ pass class AddressEntry(object): """ AddressEntry instances hold and manage details of a person """ def __init__(self, first_name=None, family_name=None, email_address=None, date_of_birth=None): """Initialize attributes first_name, family_name and date_of_birth. Each argument should be a string. date_of_birth should be of the form "MM DD, YYYY" """ self.first_name = first_name self.family_name = family_name self.email_address = email_address self.date_of_birth = date_of_birth ##### Main Section if __name__ == "__main__": address_book = AddressBook() person1 = AddressEntry("Eric", "Idle", None, "March 29, 1943") print(person1)
############Python 3 ##### Classes Section class AddressBook: """ AddressBook instances hold and manage a list of people """ pass class AddressEntry: """ AddressEntry instances hold and manage details of a person """ def __init__(self, first_name=None, family_name=None, email_address=None, date_of_birth=None): """Initialize attributes first_name, family_name and date_of_birth. Each argument should be a string. date_of_birth should be of the form "MM DD, YYYY" """ self.first_name = first_name self.family_name = family_name self.email_address = email_address self.date_of_birth = date_of_birth ##### Main Section if __name__ == "__main__": address_book = AddressBook() person1 = AddressEntry("Eric", "Idle", None, "March 29, 1943") print(person1)
Page 250
All code on this page is the same, and all outputs from the code are the same in Python 3 as in Python 2.7.
Page 252-253
All code on this page is the same, and all outputs from the code is the same in Python 3 as in Python 2.7.
However, in Python 3 you don’t need to add “(object)” when defining a class – it is assumed.
It is not an error to add (object) in Python 3, it just doesn’t look as nice.
#################Python2.7 class AddressEntry(object): """ AddressEntry instances hold and manage details of a person """ def __init__(self, first_name=None, family_name=None, email_address=None, date_of_birth=None): """initialize attributes first_name, family_name and date_of_birth each argument should be a string date_of_birth should be of the form "MM DD, YYYY" """ self.first_name = first_name self.family_name = family_name self.email_address = email_address self.date_of_birth = date_of_birth def __repr__(self): """ Given an AddressEntry object self return a readable string representation """ template = "AddressEntry(first_name='%s', "+\ "family_name='%s',"+\ " email_address='%s', "+\ "date_of_birth='%s')" return template%(self.first_name, self.family_name, self.email_address, self.date_of_birth) ##### Functions Section ##### Main Section if __name__ == "__main__": address_book = AddressBook() person1 = AddressEntry("Eric", "Idle", None, "March 29, 1943") print(person1)
#################Python3 class AddressEntry: """ AddressEntry instances hold and manage details of a person """ def __init__(self, first_name=None, family_name=None, email_address=None, date_of_birth=None): """initialize attributes first_name, family_name and date_of_birth each argument should be a string date_of_birth should be of the form "MM DD, YYYY" """ self.first_name = first_name self.family_name = family_name self.email_address = email_address self.date_of_birth = date_of_birth def __repr__(self): """ Given an AddressEntry object self return a readable string representation """ template = "AddressEntry(first_name='%s', "+\ "family_name='%s',"+\ " email_address='%s', "+\ "date_of_birth='%s')" return template%(self.first_name, self.family_name, self.email_address, self.date_of_birth) ##### Functions Section ##### Main Section if __name__ == "__main__": address_book = AddressBook() person1 = AddressEntry("Eric", "Idle", None, "March 29, 1943") print(person1)
Page 254-256
All code on this page is the same, and all outputs from the code is the same in Python 3 as in Python 2.7.
However, in Python 3 you don’t need to add “(object)” when defining a class – it is assumed.
It is not an error to add (object) in Python 3, it just doesn’t look as nice.
""" Addressbook.py An address book program to store details of people I know. Stuff I'm storing is: first name family name email address date of birth [other stuff] Brendan Scott Feb 2015 """ ##### Classes Section class AddressBook(object): """ AddressBook instances hold and manage a list of people """ def __init__(self): """ Set people attribute to an empty list""" self.people = [] def add_entry(self, new_entry): """ Add a new entry to the list of people in the address book the new_entry should be an instance of the AddressEntry class""" self.people.append(new_entry) class AddressEntry(object): """ AddressEntry instances hold and manage details of a person """ def __init__(self, first_name=None, family_name=None, email_address=None, date_of_birth=None): """Initialize attributes first_name, family_name and date_of_birth. Each argument should be a string. date_of_birth should be of the form "MM DD, YYYY" """ self.first_name = first_name self.family_name = family_name self.email_address = email_address self.date_of_birth = date_of_birth def __repr__(self): """ Given an AddressEntry object self return a readable string representation """ template = "AddressEntry(first_name='%s', "+\ "family_name='%s',"+\ "email_address='%s', "+\ "date_of_birth='%s')" return template%(self.first_name, self.family_name, self.email_address, self.date_of_birth) ##### Functions Section ##### Main Section if __name__ == "__main__": address_book = AddressBook() person1 = AddressEntry("Eric", "Idle", None, "March 29, 1943") print(person1) address_book.add_entry(person1) print(address_book.people)
#################Python3 """ Addressbook.py An address book program to store details of people I know. Stuff I'm storing is: first name family name email address date of birth [other stuff] Brendan Scott Feb 2015 """ ##### Classes Section class AddressBook: """ AddressBook instances hold and manage a list of people """ def __init__(self): """ Set people attribute to an empty list""" self.people = [] def add_entry(self, new_entry): """ Add a new entry to the list of people in the address book the new_entry should be an instance of the AddressEntry class""" self.people.append(new_entry) class AddressEntry: """ AddressEntry instances hold and manage details of a person """ def __init__(self, first_name=None, family_name=None, email_address=None, date_of_birth=None): """Initialize attributes first_name, family_name and date_of_birth. Each argument should be a string. date_of_birth should be of the form "MM DD, YYYY" """ self.first_name = first_name self.family_name = family_name self.email_address = email_address self.date_of_birth = date_of_birth def __repr__(self): """ Given an AddressEntry object self return a readable string representation """ template = "AddressEntry(first_name='%s', "+\ "family_name='%s',"+\ "email_address='%s', "+\ "date_of_birth='%s')" return template%(self.first_name, self.family_name, self.email_address, self.date_of_birth) ##### Functions Section ##### Main Section if __name__ == "__main__": address_book = AddressBook() person1 = AddressEntry("Eric", "Idle", None, "March 29, 1943") print(person1) address_book.add_entry(person1) print(address_book.people)
Page 256
The code on this page is a little different. As explained in Project 7, the syntax for the open()
builtin is the same in Python 2.7 and Python 3, but Python 3 treats the files it opens differently
In code on this page, you are opening a file to write a “pickle” to. In Python 3 you need to open
the file with a “binary” modifier. That is, you need to use ‘wb’ rather than ‘w’. Similarly, to read
from a pickle file you need to open it using ‘rb’ rather than ‘r’.
When reading the pickle file, Python3 uses a different way of representing the data.
How it’s different is not relevant to the project, so you can ignore it. All you need
to do is notice that pickle has written something to the file and it’s encoded in some way.
#Python2.7 >>> import pickle >>> FILENAME = "p4k_test.pickle" >>> dummy_list = [x*2 for x in range(10)] >>> dummy_list # confirm what it looks like [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] >>> with open(FILENAME,'w') as file_object: #now dump it! pickle.dump(dummy_list,file_object) >>> # open the raw file to look at what was written >>> with open(FILENAME,'r') as file_object: # change w to r!!! print(file_object.read()) (lp0 I0 aI2 aI4 aI6 aI8 aI10 aI12 aI14 aI16 aI18 a.
#Python3 >>> import pickle >>> FILENAME = "p4k_test.pickle" >>> dummy_list = [x*2 for x in range(10)] >>> dummy_list # confirm what it looks like [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] >>> with open(FILENAME,'wb') as file_object: #now dump it! pickle.dump(dummy_list,file_object) >>> # open the raw file to look at what was written >>> with open(FILENAME,'rb') as file_object: # change w to r!!! print(file_object.read()) b'\x80\x03]q\x00(K\x00K\x02K\x04K\x06K\x08K\nK\x0cK\x0eK\x10K\x12e.' >>>
Page 258
Code is slightly different. As explained above, use ‘rb’ to open the file, rather than ‘r’
## Python2.7 Python 2.7.3 (default, Apr 14 2012, 08:58:41) [GCC] on linux2 Type "copyright", "credits" or "license()" for more information. >>> import pickle >>> FILENAME = "p4k_test.pickle" >>> with open(FILENAME,'r') as file_object: dummy_copy = pickle.load(file_object) >>> dummy_copy [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
## Python3 Python 3.3.5 (default, Mar 27 2014, 17:16:46) [GCC] on linux Type "copyright", "credits" or "license()" for more information. >>> import pickle >>> FILENAME = "p4k_test.pickle" >>> with open(FILENAME,'rb') as file_object: dummy_copy = pickle.load(file_object) >>> dummy_copy [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] >>>
Page 260
Python3 now uses cPickle when you import pickle. If it can’t find cPickle
then it falls back to using the old pickle. So don’t worry about cPickle if you’re using Python 3.
As explained above, also use ‘wb’ to open the file, rather than ‘w’
# Python 2.7 #### Imports import cPickle as pickle #### Constants SAVE_FILE_NAME = "address_book.pickle" def save(self): with open(SAVE_FILE_NAME, 'w') as file_object: pickle.dump(self, file_object)
# Python 3 #### Imports import pickle #### Constants SAVE_FILE_NAME = "address_book.pickle" def save(self): with open(SAVE_FILE_NAME, 'wb') as file_object: pickle.dump(self, file_object)
Page 261
All code on this page is the same, and all outputs from the code are the same in Python 3 as in Python 2.7.
Page 262
Code is different:
* As explained above, use ‘rb’ to open the file, rather than ‘r’
#Python 2.7 def load(self): """ Load a pickled address book from the standard save file """ with open(SAVE_FILE_NAME, 'r') as file_object: self.address_book = pickle.load(file_object)
#Python 3 def load(self): """ Load a pickled address book from the standard save file """ with open(SAVE_FILE_NAME, 'rb') as file_object: self.address_book = pickle.load(file_object)
#Python 3 """ Addressbook.py An address book program to store details of people I know. Stuff I'm storing is: first name family name email address date of birth [other stuff] Brendan Scott Feb 2015 """ #### Imports import pickle #### Constants SAVE_FILE_NAME = "address_book.pickle" ##### Classes Section class AddressBook(object): """ AddressBook instances hold and manage a list of people """ def __init__(self): """ Set people attribute to an empty list""" self.people = [] def add_entry(self, new_entry): """ Add a new entry to the list of people in the address book the new_entry should be an instance of the AddressEntry class""" self.people.append(new_entry) def save(self): """ save a copy of self into a pickle file""" with open(SAVE_FILE_NAME, 'wb') as file_object: pickle.dump(self, file_object) class AddressEntry(object): """ AddressEntry instances hold and manage details of a person """ def __init__(self, first_name=None, family_name=None, email_address=None, date_of_birth=None): """Initialize attributes first_name, family_name and date_of_birth. Each argument should be a string. date_of_birth should be of the form "MM DD, YYYY" """ self.first_name = first_name self.family_name = family_name self.email_address = email_address self.date_of_birth = date_of_birth def __repr__(self): """ Given an AddressEntry object self return a readable string representation """ template = "AddressEntry(first_name='%s', "+\ "family_name='%s',"+\ "email_address='%s', "+\ "date_of_birth='%s')" return template%(self.first_name, self.family_name, self.email_address, self.date_of_birth) class Controller(object): """ Controller acts as a way of managing the data stored in an instance of AddressBook and the user, as well as managing loading of stored data """ def __init__(self): """ Initialise controller. Look for a saved address book If one is found,load it, otherwise create an empty address book. """ self.address_book = AddressBook() person1 = AddressEntry("Eric", "Idle", "March 29, 1943") self.address_book.add_entry(person1) def load(self): """ Load a pickled address book from the standard save file """ with open(SAVE_FILE_NAME, 'rb') as file_object: self.address_book = pickle.load(file_object) ##### Functions Section ##### Main Section if __name__ == "__main__": controller = Controller() print(controller.address_book.people)
Page 266
All code on this page is the same, and all outputs from the code are the same in Python 3 as in Python 2.7.
Page 267
Code is different:
* import pickle (not import cPickle as pickle)
* As explained above, use ‘rb’ to open the file, rather than ‘r’
#Python 3 #### Imports import pickle import os.path #### Constants SAVE_FILE_NAME = "address_book.pickle" class Controller(object): """ Controller acts as a way of managing the data stored in an instance of AddressBook and the user, as well as managing loading of stored data """ def __init__(self): """ Initialize controller. Look for a saved address book If one is found,load it, otherwise create an empty address book. """ self.address_book = self.load() if self.address_book is None: self.address_book = AddressBook() def load(self): """ Load a pickled address book from the standard save file """ #TODO: Test this method if os.path.exists(SAVE_FILE_NAME): with open(SAVE_FILE_NAME, 'rb') as file_object: return pickle.load(file_object) else: return None
Page 270-272
This code uses raw_input. As explained in Python 3/Project 3 you need to either replace
all references to raw_input with just input or add new line raw_input = input
in the Constants section
#Python 3 #### Constants raw_input = input SAVE_FILE_NAME = "address_book.pickle" INSTRUCTIONS = """Address Book Application (Python For Kids For Dummies Project 9) Press: a to add an entry d to display a list of all entries in summary form. i to print these instructions again q to quit. """ CONFIRM_QUIT_MESSAGE = 'Are you sure you want to quit (Y/n)? ' def __init__(self): """ Initialize controller. Look for a saved address book If one is found,load it, otherwise create an empty address book. """ self.address_book = self.load() if self.address_book is None: self.address_book = AddressBook() self.run_interface() def run_interface(self): """ Application's main loop. Get user input and respond accordingly""" print(INSTRUCTIONS) while True: command = raw_input("What would you like to do? ") if command == "a": self.add_entry() elif command == "q": if confirm_quit(): print("Saving") self.address_book.save() print("Exiting the application") break elif command == "i": print(INSTRUCTIONS) elif command == "d": self.display_summaries() else: template = "I don't recognise that instruction (%s)" print(template%command) def add_entry(self): """query user for values to add a new entry""" print("In add_entry") def display_summaries(self): """ display summary information for each entry in address book""" print("In display_summaries")
Page 274
Changes necessary for the code to work in Python 3:
* imports cPickle – just import pickle
* uses raw_input – Need to add a line raw_input = input in the Constants section
* uses ‘r’ and ‘w’ when opening files for pickle – need to use ‘rb’ and ‘wb’
#Python 3 """ Addressbook.py An address book program to store details of people I know. Stuff I'm storing is: first name family name email address date of birth [other stuff] Brendan Scott Feb 2015 """ #### Imports import pickle import os.path #### Constants raw_input = input SAVE_FILE_NAME = "address_book.pickle" INSTRUCTIONS = """Address Book Application (Python For Kids For Dummies Project 9) Press: a to add an entry d to display a list of all entries in summary form. i to print these instructions again q to quit. """ CONFIRM_QUIT_MESSAGE = 'Are you sure you want to quit (Y/n)? ' SUMMARY_TEMPLATE = "%s %s DOB: %s email: %s" ##### Classes Section class AddressBook(object): """ AddressBook instances hold and manage a list of people """ def __init__(self): """ Set people attribute to an empty list""" self.people = [] def add_entry(self, new_entry): """ Add a new entry to the list of people in the address book the new_entry should be an instance of the AddressEntry class""" self.people.append(new_entry) def save(self): """ save a copy of self into a pickle file""" with open(SAVE_FILE_NAME, 'wb') as file_object: pickle.dump(self, file_object) class AddressEntry(object): """ AddressEntry instances hold and manage details of a person """ def __init__(self, first_name=None, family_name=None, email_address=None, date_of_birth=None): """Initialize attributes first_name, family_name and date_of_birth. Each argument should be a string. date_of_birth should be of the form "MM DD, YYYY" """ self.first_name = first_name self.family_name = family_name self.email_address = email_address self.date_of_birth = date_of_birth def __repr__(self): """ Given an AddressEntry object self return a readable string representation """ template = "AddressEntry(first_name='%s', "+\ "family_name='%s',"+\ " email_address='%s', "+\ "date_of_birth='%s')" return template%(self.first_name, self.family_name, self.email_address, self.date_of_birth) class Controller(object): """ Controller acts as a way of managing the data stored in an instance of AddressBook and the user, as well as managing loading of stored data """ def __init__(self): """ Initialize controller. Look for a saved address book If one is found,load it, otherwise create an empty address book. """ self.address_book = self.load() if self.address_book is None: self.address_book = AddressBook() self.run_interface() def load(self): """ Load a pickled address book from the standard save file """ if os.path.exists(SAVE_FILE_NAME): with open(SAVE_FILE_NAME, 'rb') as file_object: address_book = pickle.load(file_object) return address_book else: return None def run_interface(self): """ Application's main loop. Get user input and respond accordingly""" print(INSTRUCTIONS) while True: command = raw_input("What would you like to do? ") if command == "a": self.add_entry() elif command == "q": if confirm_quit(): print("Saving") self.address_book.save() print("Exiting the application") break elif command == "i": print(INSTRUCTIONS) elif command == "d": self.display_summaries() else: template = "I don't recognise that instruction (%s)" print(template%command) def add_entry(self): """query user for values to add a new entry""" print("Adding a new person to the address book") print("What is the person's:") first_name = raw_input("First Name? ") if first_name == "q": print("Not Adding") return family_name = raw_input("Family Name? ") if family_name == "q": print("Not Adding") return email_address = raw_input("Email Address? ") if email_address == "q": print("Not Adding") return DOB_PROMPT = "Date of Birth (Month day, year)? " date_of_birth = raw_input(DOB_PROMPT) if date_of_birth == "q": print("Not Adding ") return entry = AddressEntry(first_name, family_name, email_address, date_of_birth) self.address_book.add_entry(entry) values = (first_name, family_name) print("Added address entry for %s %s\n"%values) def display_summaries(self): """ display summary information for each entry in address book""" print("Displaying Summaries") for index, e in enumerate(self.address_book.people): values = (e.first_name, e.family_name, e.date_of_birth, e.email_address) entry = SUMMARY_TEMPLATE%values print("%s: %s"%(index+1, entry)) # start numbering at 1 ##### Functions Section def confirm_quit(): """Ask user to confirm that they want to quit default to yes Return True (yes, quit) or False (no, don't quit) """ spam = raw_input(CONFIRM_QUIT_MESSAGE) if spam == 'n': return False else: return True ##### Main Section if __name__ == "__main__": controller = Controller()