1 Format Interger
<Learning Python 4th edition>
The following module, formats.py, defines string formatting utilities for importers, but also checks its name to see if it is being run as a top-level script; if so, it tests and uses arguments listed on the system command line to run a canned or passed-in test. In Python, the sys.argv list contains command-line arguments—it is a list of strings reflecting words typed on the command line, where the first item is always the name of the script being run:
"""
Various specialized string display formatting utilities.
Test me with canned self-test or command-line arguments.
"""
def commas(N):
"""
format positive integer-like N for display with
commas between digit groupings: xxx,yyy,zzz
"""
digits = str(N)
assert(digits.isdigit())
result = ""
while digits:
digits, last3 = digits[:-3], digits[-3:]
result = (last3 + "," + result) if result else last3
return result
def money(N, width = 0):
"""
format number N for display with commas, 2 decimal digits,
leading $ and sign, and optional padding: $ -xxx,yyy,zzz
"""
sign = "-" if N < 0 else ""
N = abs(N)
whole = commas(int(N))
fract = ("%.2f" %N)[-2:]
format = "%s%s.%s" %(sign, whole, fract)
return "$%*s" %(width, format)
if __name__ == "__main__":
def selftest():
tests = 0, 1
tests += 12, 123, 1234, 12345, 123456, 1234567
tests += 2 ** 32, 2 ** 100
for test in tests:
print commas(test)
print ""
tests = 0, 1, -1, 1.23, 1., 1.2, 3.14259
tests += 12.34, 12,344, 12.345, 12.346
tests += 2 ** 32, (2 ** 32 + .2345)
tests += 1.2345, 1.2, 0.2345
tests += -1.2345, -1.2, -0.2345
tests += -(2 ** 32), -(2**32 + .2345)
tests += (2 ** 100), -(2 ** 100)
for test in tests:
print "%s [%s]" %(money(test, 17), test)
import sys
if len(sys.argv) == 1:
selftest()
else:
print money(float(sys.argv[1]), int(sys.argv[2]))
Output example:
2 Lists the namespaces of other modules
M.name
M.__dict__["name"]
sys.modules["M"].name
getattr(M, "name")
Here is a module named mydir.py that puts these ideas to work to implement a customized version of the built-in dir function. It defines and exports a function called listing, which takes a module object as an argument and prints a formatted listing of the module’s namespace:
"""
mydir.py: a module that lists the namespace of other modules
"""
seplen = 60
sepchr = "-"
def listing(module, verbose = True):
sepline = sepchr * seplen
if verbose:
print sepline
print "name: ", module.__name__, "file: ", module.__file__
print sepline
count = 0
for attr in module.__dict__:
print "%02d %s" %(count, attr)
if attr.startswith('__'):
print "<built-in name>"
else:
print getattr(module, attr)
count += 1
if verbose:
print sepline
print module.__name__, "has %d names" %(count)
print sepline
if __name__ == "__main__":
import mydir
listing(mydir)
output example:
a.py:
import b
b.spam('gumby')
b.py:
def spam(text):
print(text, 'spam')
3 A Generic Display Tool
A class that displays accurate class names and formats all attributes of an instance of any class.
# classtools.py
"Assorted class utilities and tools"
class AttrDisplay(object):
"""
Provides an inheritable print overload method that displays
instances with their class names and a name=value pair for
each attribute stored on the instance itself (but not attrs
inherited from its classes). Can be mixed into any class,
and will work on any instance.
"""
def gatherAttrs(self):
attrs = []
for key in sorted(self.__dict__):
attrs.append("%s=%s" %(key, getattr(self, key)))
return ", ".join(attrs)
def __str__(self):
return "[%s: %s]" %(self.__class__.__name__, self.gatherAttrs())
if __name__ == "__main__":
class TopTest(AttrDisplay):
count = 0
def __init__(self):
self.attr1 = TopTest.count
self.attr2 = TopTest.count + 1
TopTest.count += 2
class SubTest(TopTest):
pass
x, y = TopTest(), SubTest()
print(x) # Show all instance attrs
print(y) # Show lowest class name
test output:
4 Python Class Studying Example: Person & Manager
# File person.py (final)
from classtools import AttrDisplay # Use generic display tool
class Person(AttrDisplay):
"""
Create and process person records
"""
def __init__(self, name, job = None, pay = 0):
self.name = name
self.job = job
self.pay = pay
def lastName(self): # Assumes last is last
return self.name.split()[-1]
def giveRaise(self, percent): # percent must be 0..1
self.pay = int(self.pay * (1 + percent))
"""
def __str__(self):
return "[Person: %s, %s]" %(self.name, self.pay)
"""
class Manager(Person):
"""
A customed Person with special requirements
"""
def __init__(self, name, pay):
Person.__init__(self, name, "mgr", pay)
def giveRaise(self, percent, bonus = .10):
# self.pay = int(self.pay * (1 + percent + bonus))
Person.giveRaise(self, percent + bonus) # self is must
if __name__ == "__main__":
bob = Person(name = 'Bob Smith')
sue = Person('Sue Jones', job = 'dev', pay = 100000)
print(bob)
print(sue)
print(bob.lastName(), sue.lastName())
sue.giveRaise(.10)
print(sue)
tom = Manager("Tom Jones", 50000)
tom.giveRaise(.10)
print(tom.lastName())
print(tom)
"""
print("--All three--")
for object in (bob, sue, tom):
object.giveRaise(.10)
print(object)
"""
test output:
5 Storing Objects on a Shelve Database
Object persistence is implemented by three standard library modules, available in every Python:
pickle
Serializes arbitrary Python objects to and from a string of bytes
dbm (named anydbm in Python 2.6)
Implements an access-by-key filesystem for storing strings
shelve
Uses the other two modules to store Python objects on a file by key
# File makedb.py: store Person objects on a shelve database
from person import Person, Manager # Load our classes
bob = Person("Bob Smith") # Re-create objects to be stored
sue = Person("Sue Jones", job = "deb", pay = 100000)
tom = Manager("Tom Jones", 5000)
import shelve
db = shelve.open("persondb") # Filename where objects are stored
for obj in (bob, sue, tom): # Use object's name attr key
db[obj.name] = obj # Store object on shelve by key
db.close() # Close after making changes

Updating Objects on a Shelve:
# File updatedb.py: update Person object on database
import shelve
db = shelve.open("persondb")
for key in sorted(db):
print(key, "\t=>", db[key])
sue = db["Sue Jones"]
sue.giveRaise(.10)
db["Sue Jones"] = sue
db.close()

On the way...