Design by Contract for Python

Terence Way terry at wayforward.net
Thu May 15 08:49:14 EDT 2003


Thanks for the info.

 > Metaclasses offer a neat, cool way of grouping related functions
 > like preconditions and posconditions...

Meta-classes are, in fact, the technique used by Daniel Arbuckle
in his excellent PyDBC package, see
     http://savannah.nongnu.org/projects/pydbc/
Although I like the "grouping" that you propose.  But I'm not sure it
would work with inheritance ("virtual" functions).  Or variable
arguments.  I wish instance methods could have their own dict,
just like static functions.  Then you could do:
     class foo:
          def func(self, a, b):
                ...
          func.pre = ...
          func.post = ...

Note that I'm proposing something completely different, see
     http://www.wayforward.net/pydbc/

The problems with having the pre-condition function return the
saved values is:
* there is no guarantee that the pre-condition function will be
   called for inherited classes; and
* a pre-condition can trigger an assertion yet the old-values still
   need to be saved.

"Weakening the pre-condition" is done in Eiffel, and should be
done by any DBC for Python, so inherited classes can replace
base classes.  Example:

     class YourBase:
         def foo(self, a, b, c):
             """pre:
                 0 < a < b < c < 256
             """

Someone can go code to this specification, going through some
effort to make sure the arguments a, b, c are correct.  Next, define a
new class:

     class BelongToUs(YourBase):
         def foo(self, a, b, c):
             ...
(is it true that all YourBase are BelongToUs? :-)

Now we have a problem.  We can't add more preconditions,
because if we did, the code that was written to call YourBase.foo
will break.

The only thing we can do is to weaken the pre-condition.  In Eiffel
this done automatically by ORing a method's pre-conditions with
the pre-conditions of any overridden method... if a function's pre-
conditions break, then any super-classes are searched for the
same method, and its preconditions tested.

So, an implementation will look for the first pre-condition that
works, and must test for all post-conditions.

Conclusion: either the pre-condition function returns a tuple of its
result (valid, old-values) OR a separate function must be written to
save old values.

I'm beginning to think that the complexities of DBC are not in
"installing" the condition check functions, but in coming up with a
system that:
a) can be retrofitted into existing code;
b) matches Eiffel's well-thought-out semantics; and
c) doesn't require a lot of programmer effort.

Thanks again.






More information about the Python-list mailing list