computer science 111 fundamentals of programming i persistent data models object serialization
TRANSCRIPT
Computer Science 111
Fundamentals of Programming IPersistent Data Models
Object Serialization
from bank import Bank
def createBank(numAccounts = 1): """Returns a new bank with the given number of accounts.""" bank = Bank() upperPin = numAccounts + 1000 for pinNumber in range(1000, upperPin): bank.add(SavingsAccount('Ken', str(pinNumber))) return bank
Helper Function to Create a Bank
bank = createBank(5)
Transience and Persistence
• Data in computer memory are transient and are lost when the program quits
• Data become persistent when they can be saved to a file and reloaded from a file
File storageData model
save
load
Saving a Savings Account
def save(self, fileObj): # In SavingsAccount fileObj.write(self.name + '\n') fileObj.write(self.pin + '\n') fileObj.write(str(self.balance) + '\n')
Include a method for writing an account’s info to a text file:
>>> a = SavingsAccount('Ken', '8809', 500.00)
>>> fileObj = open('account.txt', 'w')
>>> a.save(fileObj)
>>> fileObj.close()
Run the method in the shell and then inspect the file:
Saving an Entire Bank
def save(self, fileName): # In Bank fileObj = open(fileName, 'w') for account in self.accounts.values(): account.save(fileObj) fileObj.close()
Include a method for writing an bank’s info to a text file:
>>> bank = createBank(5)
>>> bank.save('bank.txt')
Run the method in the shell and then inspect the file:
Class Methods vs Instance Methods
class MyClass:
def instanceMethod(self): return 'I am an instance method.' @classmethod def classMethod(cls): return 'I am a class method.'
Define a class method and an instance method:
>>> print(MyClass.classMethod())I am a class method.
>>> obj = MyClass()
>>> print(obj.instanceMethod())I am an instance method.
Try both methods in the shell:
Class Methods vs Instance Methods
• Like a class variable, a class method is used with the class’s name
• An instance method is always used with an instance
• Class methods can see class variables but not instance variables
• Instance methods can see both kinds of variables
Why Use Class Methods?
• Class methods are often used to create and return instances of those classes
• Such methods are also called factory methods
>>> class MyClass: @classmethod def getInstance(cls): return MyClass()
>>> obj = MyClass.getInstance()
Example:
Loading a Savings Account
@classmethoddef load(cls, fileObj): # In SavingsAccount name = fileObj.readline().strip() pin = fileObj.readline().strip() balance = fileObj.readline().strip() if not name: return None else: return SavingsAccount(name, pin, float(balance))
Include a class method to read an account’s info from a text file and return a new instance with that info:
>>> fileObj = open('account.txt', 'r')
>>> a = SavingsAccount.load(fileObj)
>>> print(a)
Run the method in the shell and then inspect the account:
Loading an Entire Bank
@classmethoddef load(cls, fileName): # In Bank fileObj = open(fileName, 'r') bank = Bank() while True: a = SavingsAccount.load(fileObj) if not a: break else: bank.addAccount(a) fileObj.close() return bank
Include a class method to load accounts and create a bank:
>>> bank = Bank.load('bank.txt')
>>> print(bank)
Test the method in the shell and then inspect the account:
Problems
• Lots of manual labor to output and input the attributes of accounts as text
• Must change this code every time we modify the structure of an account (add an address attribute, etc.)
• A text file is insecure and inefficient
Solution: Pickle the Data
• Pickling automates the process of converting an object to a form suitable for file storage
• Unpickling automates the process of converting data from file storage back to the appropriate objects
File storageData model
pickling
unpickling
The pickle Module
dump(obj, fileObj) # Pickles obj and writes it to fileObj
load(fileObj) # Reads an object from fileObj, # unpickles it, and returns it
# Raises an exception if the end of # the file is reached
Using pickle for Output
>>> import pickle
>>> fileObj = open('test.dat', 'wb')
>>> pickle.dump('Hi there!', fileObj)
>>> fileobj.close()
Must use the argument “wb” or “rb” when opening a file for output or input
The “b” stands for “byte”
Using pickle for Input
>>> import pickle
>>> fileObj = open('test.dat', 'wb')
>>> pickle.dump('Hi there!', fileObj)
>>> fileobj.close()
>>> fileObj = open('test.dat', 'rb')
>>> s = pickle.load(fileObj)
>>> print(s)Hi there!
Using pickle with Accounts
>>> import pickle
>>> fileObj = open('test.dat', 'wb')
>>> account = SavingsAccount('Ken', '8809', 500.00)
>>> pickle.dump(account, fileObj)
>>> fileobj.close()
>>> fileObj = open('test.dat', 'rb')
>>> account = pickle.load(fileObj)
>>> print(account)Blah blah blah
Saving an Entire Bank (Text)
def save(self, fileName): # In Bank fileObj = open(fileName, 'w') for account in self.accounts.values(): account.save(fileObj) fileObj.close()
Include a method for writing an bank’s info to a text file:
>>> bank = createBank(5)
>>> bank.save('bank.txt')
Run the method in the shell and then inspect the file:
Saving an Entire Bank (Pickled)
def save(self, fileName): # In Bank fileObj = open(fileName, 'wb') for account in self.accounts.values(): pickle.dump(account, fileObj) fileObj.close()
Include a method for writing an bank’s info to a text file:
>>> bank = createBank(5)
>>> bank.save('bank.dat')
Run the method in the shell and then inspect the file:
Loading an Entire Bank (Text)
@classmethoddef load(cls, fileName): # In Bank fileObj = open(fileName, 'r') bank = Bank() while True: a = SavingsAccount.load(fileObj)) if not a: break else: bank.addAccount(a) fileObj.close() return bank
Include a class method to load accounts and create a bank:
>>> bank = Bank.load('bank.txt')
>>> print(bank)
Test the method in the shell and then inspect the account:
Loading an Entire Bank (Pickled)
@classmethoddef load(cls, fileName): # In Bank fileObj = open(fileName, 'rb') bank = Bank() try: while True: a = pickle.load(fileObj) bank.addAccount(a) except Exception(e): fileObj.close() return bank
Include a class method to load accounts and create a bank:
>>> bank = Bank.load('bank.dat')
>>> print(bank)
Test the method in the shell and then inspect the account: