[Python-ideas] Explicit variable capture list
Ethan Furman
ethan at stoneleaf.us
Tue Jan 26 11:55:04 EST 2016
On 01/25/2016 03:34 PM, Steven D'Aprano wrote:
> 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 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)
I like that syntax.
Currently, something not too ugly would be to use descriptors --
something like:
from dbc import require, ensure
class Frobnigate(object):
@require
def spammer(self, desc):
desc.assertInRange(arg1, 0, 99)
@spammer
def _spammer(self, arg1, arg2):
return arg1 // arg2 + arg1
@spammer.ensure
def spammer(self, desc, res):
if desc.arg2 % 2 == 1:
desc.assertEqual(res % 2, 1)
else:
desc.assertEqual(res % 2, 0)
@ensure
def egger(self, desc, res):
desc.assertIsType(res, str)
@egger
def _egger(self, egg_type):
'scrambled, poached, boiled, etc'
return egg_type
Where 'desc' in the above code is 'self' for the descriptor so saved
arguments could be accessed, etc.
I put a leading underscore on the body so it could be kept separate and
more easily subclassed without losing the DBC portions.
If 'require' is not needed, one can use 'ensure'; both create the DBC
object which would take care of calling any/all requires, then the
function, then any/all ensures, and also grabbing and saving the
function signature and actual parameters.
--
~Ethan~
More information about the Python-ideas
mailing list