@decorators

Mark Bottjer mark_bottjer at hotmail.com
Wed Aug 11 13:33:11 EDT 2004


Mark 'Kamikaze' Hughes wrote:
> You can already do pre- and post-conditions without new syntax:
> 
> import types
> def intdiv(a, b):
>     # preconditions
>     assert type(a) == types.IntType
>     assert type(b) == types.IntType
>     assert b != 0
>     rc = None
>     try:
>         # body
>         rc = a // b; return rc
>     finally:
>         # postconditions
>         assert type(rc) == types.IntType
> 
> If assignment was an expression, that return would be a little nicer,
> but it's acceptable.

Sorry, but to me this is ugly. The preconditions aren't so bad (in fact, 
much of my code has just such lines in it), but that postcondition block 
is awful. It looks arbitrary, hides the real "meat" of the function, and 
requires the construction of an exception frame when one shouldn't 
really be needed. It works, certainly, but I think we'll have to "agree 
to disagree" about how acceptable this syntax is. :)

 > Mark Bottjer <mark_bottjer at hotmail.com>
 > wrote on Fri, 06 Aug 2004 16:10:37 -0400:
 >
 >> Exactly. What's more, I don't think that decorators are really the
 >> ideal way to express DBC, either. For one thing, pre and post
 >> conditions often want access to at least the argument list, and often
 >> to the internal variables of the definition. I don't think that this
 >> will be possible with the decorators as proposed, since they are
 >> outside the scope of the function.

After more thought, I think that it might be possible using decorators 
and subfunctions. Shouldn't the following be workable?

import types
@pre_and_post
def intdiv(a, b):
     def __pre():
         assert type(a) == types.IntType
         assert type(b) == types.IntType
         assert b != 0
     def __post():
         assert type(rc) == types.IntType
     return a // b

Where pre_and_post effectively wraps intdiv with the statement sequence:

   intdiv.__pre()
   try:
     return intdiv( *args)
   finally:
     intdiv.__post()

This is functionally equivalent to your example (it even still requires 
the try/finally). But I suggest that this version is more understandable 
because it breaks the code up by what it does: __pre collects all the 
preconditions, __post collects all the postconditions, and the body is 
left alone. Theoretically, we could even globally enable or disable DBC 
by having pre_and_post switch on some global variable, which would not 
be possible with the conditions coded inline.

I'm not savvy enough with Python internals to code this up myself, but 
I'm sure someone out there either can, or can tell me why it won't work.

   -- Mark



More information about the Python-list mailing list