Newbie - 1st Program
Bruno Desthuilliers
bdesth.nospam at removeme.free.fr
Mon Nov 10 07:58:26 EST 2003
Mark Smith wrote:
> Hi,
Ho
(snip)
> It seems to work - great - but how would you make this more 'elegant' - I'm
> sure it's horrible to an experienced hacker...
Not so bad. Well, for a first program, it's even pretty good. I dont see
anything that would make me scream. But I'm not sure I do qualify as "an
experienced hacker" either !-)
Now I'll take Ben Finney's good advices one step further, and show you
how I'd structure this. You may find the exemple somewhat complex or
confusing, but it may help you or other (well, I hope it will) learn
some of Python's features and common idioms, and how to cleanly
modularize code.
Any question welcome, of course !-)
> # Cross-Connect Calculator
>
> # (c)2003 Mark A Smith
> # Calculates the number of possible routes for a cross connect
> # given a certain number of ingress & egress ports.
>
> # Get number of ports from user
>
> inputPorts = input("Enter number of Input Ports: ")
> outputPorts = input("Enter number of Output Ports: ")
You should not use input(). Try entering anything else than a positive
integer value, and you'll know why.
Here is a sample data acquisition code :
def int_input(msg = ""):
while (1):
try:
user_input = raw_input(msg)
except EOFError: # user cancelled with ctrl+d
print "\n"
val = None
break
try:
val = int(user_input)
except ValueError:
# not an integer
print "'%s' is not a valid input\n" % user_input
print "(ctrl+d to cancel)\n"
else:
# value is an int
break
# return an int, or None if user cancelled
return val
BTW, if you expect to reuse your code in a different context (like, for
example, a GUI, or batch processing, etc), you should separate data
acquisition and display from computing. So you would have a function for
computing, and functions for data acquisition and display
this may look like this :
def countConnectionRoutes(inputPorts, outputPorts):
""" countConnectionRoutes()
Compute and return number of possible connection routes
for a given input ports count and a given
output ports count
"""
# NB : you should definitively rewrite this
# according to Alex Martelli's observations
totalPorts = float(inputPorts) + float(outputPorts)
crossConnects = (totalPorts / 2) * (totalPorts - 1)
return int(crossConnects)
# one very nice thing about Python is having functions as
# first class citizens. It allows useful things like passing
# functions as arguments to other functions.
def uiCountConnectionRoutes(getDataFun, displayDataFun):
""" uiCountConnectionRoutes()
Compute number of possible connection routes
Ask the number or in and out ports to the user,
using getDataFun and display result using
displayDataFun
in : getDataFun
a function that takes a message string, and
return an int or None if user cancelled
in : displayDataFun
a functio that take a message string
"""
inputPorts = getDataFun("Enter number of Input Ports: ")
if inputPorts is None:
return
outputPorts = getDataFun("Enter number of Output Ports: ")
if outputPorts is None:
return
crossConnects = countConnectionRoutes(inputPorts, outputPorts)
# I split this in 2 line since it wraps in my newsreader !-)
msg = "You have %d possible connection routes." % crossConnects
displayDataFun(msg)
# a very simple wrapper
def displayData(msg):
print "%s\n" % msg
# a main function to use this module as a program
def main(argv):
# the retun status. It may be useful on some OS
# usually, 0 means 'ok', 1 means 'program error',
# and 2 means 'wrong args'
status = 0
# another fine thing with Python is the possibility
# to define nested functions that can access vars in
# the enclosing function (here, the 'argv' argument)
def usage(msg = ""):
write = sys.stderr.write
if len(msg):
write("%s\n" % msg)
write("usage : %s [nb_input_ports nb_output_ports]\n" % argv[0])
write("if called with no args, values will be asked to the user\n")
# act according to the args passed to the command line
# remember that argv[0] is usually the name of the program
if len(argv) == 3 :
# called with 2 command line args,
# may be used for batch processing
try: # check args validity
inputPorts = int(argv[1])
outputPorts = int(argv[2])
except ValueError:
usage("incorrect args : %s %s" % (argv[1], argv[2]))
status = 2
else: # args ok
crossConnects = countConnectionRoutes(inputPorts, outputPorts)
# may be used for batch processing, so we keep output
# to its minimum
print crossConnects
elif len(argv) == 1:
# no args, so we go for interactive version
uiCountConnectionRoutes(int_input, displayData)
else:
# wrong arg count
usage("incorrect args count : %d" % (len(argv) - 1))
status = 2
return status
# run as a program only if called as a program
# (if this module is imported in another one,
# __name__ will be set to the real name of the module)
if __name__ == '__main__':
import sys
status = main(sys.argv)
sys.exit(status)
It may seems a bit overcomplicated, but this allow you to reuse code in
different contexts. You can use the computation function without any
interactive in/out, or use the 'ui' wrapper function with any functions
that has the right param list and return values, or simply use it as a
program, here again with the choice of passing args to the command line
or using the program interactively.
Note that there are still some points to fix (like user entering
negative int values - try it, it's somewhat funny -, or correcting the
countConnectionRoutes() function), but _this_ is your job !-)
HTH
Bruno
More information about the Python-list
mailing list