
I was training earlier this week in a room with a view - a view of a major link road towards Cambridge City centre, and I was struck by the very different mix of vehicles travelling along the road compared to what I would expect to see in Wiltshire. And - ever keen to have new, relevant data sets available for my customers to use I kept a log to see what passed in a few minutes. Here's my data file - with in brackets my guess as to the typical number of seat sin each type of vehicle:
# As I looked out I saw ...
36 (4) cars
26 (5) taxis
10 (60) local buses
1 (60) sightseeing bus
2 (2) lorries
8 (3) vans
13 (1) cycles
1 (6) private hire car
1 (2) tandem
0 (1) motor bikes
3 (70) guided buses
3 (80) park and ride buses
Exercise set ... to produce (via a Python program) a list of transport modes, sorted by the capacity that had passed me during the survey:
munchkin:tlcpy grahamellis$ python story
local buses count: 10 number: 60
park and ride buses count: 3 number: 80
guided buses count: 3 number: 70
cars count: 36 number: 4
taxis count: 26 number: 5
sightseeing bus count: 1 number: 60
vans count: 8 number: 3
cycles count: 13 number: 1
private hire car count: 1 number: 6
lorries count: 2 number: 2
tandem count: 1 number: 2
motor bikes count: 0 number: 1
munchkin:tlcpy grahamellis$
Now - there are multiple ways to do this - here is the first one that I came up with / the program that generated the result above:
import re
record = re.compile(r'(\d+)\s+\((\d+)\)\s+(.*)')
passengers = {}
for line in open("sob"):
raw = record.findall(line)
if not raw: continue
passengers[raw[0][2]] = [int(raw[0][0]),int(raw[0][1])]
def bycapacity(that,this):
return cmp(passengers[this][1]*passengers[this][0],\
nbsp; passengers[that][1]*passengers[that][0])
modes = passengers.keys()
modes.sort(bycapacity)
for mode in modes:
print "%-20s count: %3s number: %3s" % \
nbsp; (mode,passengers[mode][0],passengers[mode][1])
Well - it's quite short. And it works. But all that double subscript and conversion stuff may cause you to draw a deep breath and say "oh dear ...", and if you had to enhance the program or re-use the data in another program, you would probably do better to start from scratch.
I decided to refactor. To take all the logic that related to a transport mode and put it into its own class, and then create obejcts for each mode. Here's the second piece of code I wrote - refactoring from my initial "spike solution":
import re
class transport(object):
record = re.compile(r'(\d+)\s+\((\d+)\)\s+(.*)')
def __init__(self, source):
values = transport.record.findall(source)
if not values:
self.created = False
else:
self.created = True
self.mode = values[0][2]
self.seats = int(values[0][1])
self.counted = int(values[0][0])
 ' @staticmethod
def factory(source):
option = transport(source)
if not option.created:
return None
return option
def __cmp__(this,that):
return that.seats * that.counted - this.seats * this.counted
def __str__(this):
return "{0:20s} seats: {1:3d} count: {2:4d}".format\
(this.mode, this.seats, this.counted)
passengers = []
for line in open("sob"):
item = transport.factory(line)
if item: passengers.append(item)
passengers.sort()
for mode in passengers:
print mode
It's longer - much longer. But it's clearer - much clearer to follow. And the logic which makes use of the objects that I created is down to a few, very simple, lines of code - allowing me to bolt together new applications using the same data, and
sharing the same logic. It's also far too easy in the first version to make a change which makes a "silly" use of the data - unintentionally introducing a bug - than in the second.
You should really write
data driven code all the time. Take the object approach; it may take you a few more minutes initially during development, and it may result in code that's a bit longer. But that extra time spent coding early on will - 99 times in 100 - pay you huge dividends during the lifetime and maintainaince of the code.
Data -
[here].
Source (without objects) -
[here].
Source (with objects) -
[here].
(written 2012-07-06, updated 2012-07-14)
Associated topics are indexed as below, or enter http://melksh.am/nnnn for individual articles
Y050 - Python - General [16] Python training - (2004-08-16)
[2017] Python - a truly dynamic language - (2009-01-30)
[2020] Learning Python - many new example programs - (2009-01-31)
[2227] Learning PHP, Ruby, Lua and Python - upcoming courses - (2009-06-11)
[2285] Great new diagrams for our notes ... Python releases - (2009-07-13)
[2367] Learning to program - how to jump the first hurdles - (2009-08-20)
[2394] Two days of demonstration scripts in Python - (2009-09-05)
[2504] Learning to program in ... - (2009-11-15)
[2778] Learning to program in Python 2 ... and / or in Python 3 - (2010-05-24)
[2822] Python training courses for use with ESRI ArcMap software - (2010-06-23)
[3076] Python through the Snow - (2010-12-01)
[3463] Busy weekend of contrasts. - (2011-10-03)
[3489] Python courses and Private courses - gently updating our product to keep it ahead of the game - (2011-10-20)
[3519] Python - current versions and implementations (CPython, Jython, IronPython etc) - (2011-11-13)
[3816] Want to escape the Olympics? Learn to program in the countryside! - (2012-07-23)
[3902] Shell - Grep - Sed - Awk - Perl - Python - which to use when? - (2012-10-22)
[3903] Python Programming class for delegates who have already self-taught the basics - (2012-10-25)
[3911] How well do you know Perl and / or Python? - (2012-11-04)
[3935] Whether you have programmed before or not, we can teach you Python - (2012-11-25)
[4236] Using Python to analyse last years forum logs. Good coding practise discussion. - (2014-01-01)
[4295] A longer Python ... training course - (2014-09-16)
[4408] Additional Python courses added to our schedule - (2015-01-29)
[4434] Public training courses - upcoming dates - (2015-02-21)
[4558] Well House Consultants - Python courses / what's special. - (2015-10-28)
[4656] Identifying the first and last records in a sequence - (2016-02-26)
[4712] A reminder of the key issues to consider in moving from Python 2 to Python 3 - (2016-10-30)
Q907 - Object Orientation and General technical topics - Object Orientation: Design Techniques [80] OO - real benefits - (2004-10-09)
[236] Tapping in on resources - (2005-03-05)
[507] Introduction to Object Oriented Programming - (2005-11-27)
[534] Design - one name, one action - (2005-12-19)
[656] Think about your design even if you don't use full UML - (2006-03-24)
[747] The Fag Packet Design Methodology - (2006-06-06)
[831] Comparison of Object Oriented Philosophy - Python, Java, C++, Perl - (2006-08-13)
[836] Build on what you already have with OO - (2006-08-17)
[1047] Maintainable code - some positive advice - (2007-01-21)
[1217] What are factory and singleton classes? - (2007-06-04)
[1224] Object Relation Mapping (ORM) - (2007-06-09)
[1435] Object Oriented Programming in Perl - Course - (2007-11-18)
[1528] Object Oriented Tcl - (2008-02-02)
[1538] Teaching Object Oriented Java with Students and Ice Cream - (2008-02-12)
[2169] When should I use OO techniques? - (2009-05-11)
[2170] Designing a heirarcy of classes - getting inheritance right - (2009-05-11)
[2327] Planning! - (2009-08-08)
[2380] Object Oriented programming - a practical design example - (2009-08-27)
[2501] Simples - (2009-11-12)
[2523] Plan your application before you start - (2009-12-02)
[2717] The Multiple Inheritance Conundrum, interfaces and mixins - (2010-04-11)
[2741] What is a factory? - (2010-04-26)
[2747] Containment, Associative Objects, Inheritance, packages and modules - (2010-04-30)
[2785] The Light bulb moment when people see how Object Orientation works in real use - (2010-05-28)
[2865] Relationships between Java classes - inheritance, packaging and others - (2010-07-10)
[2878] Program for reliability and efficiency - do not duplicate, but rather share and re-use - (2010-07-19)
[2889] Should Python classes each be in their own file? - (2010-07-27)
[2953] Turning an exercise into the real thing with extreme programming - (2010-09-11)
[2977] What is a factory method and why use one? - Example in Ruby - (2010-09-30)
[3063] Comments in and on Perl - a case for extreme OO programming - (2010-11-21)
[3085] Object Oriented Programming for Structured Programmers - conversion training - (2010-12-14)
[3260] Ruby - a training example that puts many language elements together to demonstrate the whole - (2011-04-23)
[3454] Your PHP website - how to factor and refactor to reduce growing pains - (2011-09-24)
[3607] Designing your application - using UML techniques - (2012-02-11)
[3760] Why you should use objects even for short data manipulation programs in Ruby - (2012-06-10)
[3763] Spike solutions and refactoring - a Python example - (2012-06-13)
[3844] Rooms ready for guests - each time, every time, thanks to good system design - (2012-08-20)
[3878] From Structured to Object Oriented Programming. - (2012-10-02)
[3887] Inheritance, Composition and Associated objects - when to use which - Python example - (2012-10-10)
[3928] Storing your intermediate data - what format should you you choose? - (2012-11-20)
[3978] Teaching OO - how to avoid lots of window switching early on - (2013-01-17)
[4098] Using object orientation for non-physical objects - (2013-05-22)
[4374] Test driven development, and class design, from first principles (using C++) - (2014-12-30)
[4430] The spirit of Java - delegating to classes - (2015-02-18)
[4449] Spike solution, refactoring into encapsulated object methods - good design practise - (2015-03-05)
[4628] Associative objects - one object within another. - (2016-01-20)
Some other Articles
What a difference a year makes A year ago today, a server upgrade and a new Perl exampleFancy a weekend away? Try Well House Manor in Melksham, WiltshireRuby Documentation through rdocWhen you should use Object Orientation even in a short program - Python examplezip in PythonBackquote, backtic, str and repr in Python - conversion object to stringLike a bathroom company with no plumbersShould hotel staff sit on the toilet in the customer bedrooms?Excellent Rail News - what it really means