[Python-ideas] Explicit variable capture list

Steven D'Aprano steve at pearwood.info
Mon Jan 25 18:34:55 EST 2016


On Wed, Jan 20, 2016 at 05:04:21PM -0800, Guido van Rossum wrote:
> On Wed, Jan 20, 2016 at 4:10 PM, Steven D'Aprano <steve at pearwood.info>
> wrote:
[...]
> > (I'm saving my energy for Eiffel-like require/ensure blocks
> > *wink*).
> >
> 
> Now you're making me curious.


Okay, just to satisfy your curiosity, and not as a concrete proposal at 
this time, here is a sketch of the sort of thing Eiffel uses for Design 
By Contract.

Each function or method has an (optional, but recommended) pre-condition 
and post-condition. Using a hybrid Eiffel/Python syntax, here is a toy 
example:

class Lunch:
    def __init__(self, arg):
        self.meat = self.spam(arg)

    def spam(self, n:int=5):
        """Set the lunch meat to n servings of spam."""
        require:
            # Assert the pre-conditions of the method.
            assert n >= 1
        ensure:
            # Assert the post-conditions of the method.
            assert self.meat.startswith('Spam')
            if ' ' in self.meat:
                assert ' spam' in self.meat
        # main body of the method, as usual
        serves = ['spam']*n
        serves[0] = serves.title()
        self.meat = ' '.join(serves)


The require block runs before the body of the method, and the ensure 
block runs after the body, but before the method returns to the caller. 
If either fail their assertions, the method fails and raises an 
exception.


Benefits:

- The pre- and post-conditions make up (part of) the method's
  contract, which is part of the executable documentation of 
  the method. Documentation tools can extract the ensure 
  and require sections as present them as part of the API docs.

- The compiler can turn the contract checking on or off as
  needed, with the ensure/require sections handled independently.

- Testing pre- and post-conditions is logically separate from 
  the method's implementation. This allows the implementation 
  to vary while keeping the contract the same.

- But at the same time, the contract is right there with the 
  method, not seperated in some potentially distant part of the
  code base.


I'm not going to go into detail about Design By Contract, if anyone 
wants to learn more you can start here:

https://www.eiffel.com/values/design-by-contract/introduction/

https://docs.eiffel.com/book/method/et-design-contract-tm-assertions-and-exceptions


I've just discovered there's an older PEP for something similar:

https://www.python.org/dev/peps/pep-0316/

but that uses docstrings for the contracts. I don't like that.


-- 
Steve


More information about the Python-ideas mailing list