programming by contract using "decorators"

R

Russ

In the thread I started a few days ago, I was told that "programming
by contract," could be done with "decorators." I was skeptical that
this was a good approach, but as an exercise, I tried to code it up in
a reasonably elegant form. I'd like to think I succeeded -- and I must
admit that those who told me it could be done with decorators were
right.

My code is shown below. It shows a function called "myfunction," and
another function for testing it called "myfunction_test." More
detailed explanation follows the listing. Comments and feedback are
welcome, of course.

#!/usr/bin/env python

def contract(test, check=0):
"enforce programming by contract"

if check: return test

def null(func):
def null2(*args, **keys):
return func(*args, **keys)
return null2

return null

def getarg(args, keys, num, name):

if name in keys: return keys[name]
return args[num]

def myfunction_test(myfunction):
"contract test for function myfunction"

def test(*args, **keys):

x = getarg(args, keys, 0, 'x')
y = getarg(args, keys, 1, 'y')
z = getarg(args, keys, 2, 'z')

# preconditions would go here, if there were any

result = myfunction(x, y, z) # execute function

assert result == x**2 + 3 * y + z # post-condition

return result

return test

#=======================================

CheckContracts = 1

@contract(myfunction_test, CheckContracts)

def myfunction(x, y, z): return x**2 + 3 * y + z

print myfunction(4, z=1, y=3)

------------------- end of listing ---------------------

Here's what is going on. At the bottom of the listing, you will see
the definition of a function called "myfunction," followed by a call
of the function. It's a trivial function, but I gave it three
arguments just to test passing them out of order by keyword.

Just above the definition of "myfunction" is a "decorator" called
"contract," which takes two arguments. The first argument specifies
the name of the self-test contract function, which is
"myfunction_test" in this case. The second argument is used to enable
or disable the contract tests.

Note that I could have just called the decorator "myfunction_test" and
omitted the "contract" decorator, but I think this form, although
slightly less efficient, is more readable. It also allows the enabling/
disabling logic to be put in one function rather than having to repeat
it in every contract test function.

Dealing with the arguments was not a trivial matter -- at least not
for me. I had to experiment a bit to get it right. The "getarg"
function is simply a utility for parsing the ordered and keyword
arguments. It's very simple, but if something like this already
exists, please let me know. Thanks.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top