[Python-ideas] Repurpose `assert' into a general-purpose check

Soni L. fakedme+py at gmail.com
Tue Nov 28 09:02:31 EST 2017



On 2017-11-28 11:36 AM, Nick Coghlan wrote:
> On 28 November 2017 at 15:41, Steven D'Aprano <steve at pearwood.info> wrote:
>> On Tue, Nov 28, 2017 at 05:12:36AM +0300, Ivan Pozdeev via Python-ideas wrote:
>>> Unlike C, Python does the aforementioned checks all the time, i.e. it's
>>> effectively always in "debug mode".
>> Apart from -O which disables assertions. But in any case, the best use
>> of assertions is not checking things which the interpreter is going to
>> do anyway, but checking things which the interpreter can not and does
>> not check automatically: your program logic. There is no way that the
>> Python interpreter is going to do this check automatically, unless I
>> write the assertion:
>>
>> assert 0 <= r < abs(y)
>>
>> That is copied straight out of one of my functions.
> I'll make the same observation I usually do each time one of these
> threads comes up:
>
> * I'm opposed to making assert substantially different from the way it works now
> * I'm in favour of adding a new "ensure()" builtin that encapsulates
> the check-and-raise logic
>
> The reasons I prefer this approach:
>
> - assert is a statement *solely* so that the compiler can optimise it
> out. If it's not optional,
>    it doesn't need to be a statement any more
> - if the existing assert statements are left alone, there are no
> performance or compatibility
>    concerns for folks that rely on the current behaviour
> - if it's a function, it doesn't need to be called "assert", it can use the more
>    imperative term "ensure" (meaning "ensure this condition is true
> before continuing")
> - if it's a function, it can easily be emulated on old versions via
> compatibility libraries
> - "ensure() is required, assert is optional" is a better answer to
> complaints about
>    assertions being optional than suggesting "if cond: raise AssertionError(msg)"
>    as a reasonable alternative to "assert cond, msg"
> - if it's a function, we get access to all the regular function
> machinery, so we're
>    not restricted to positional-only arguments the way the assert statement is
>
> My initial proposed behaviour for the function:
>
>      def ensure(cond, msg=None, exc_type=RuntimeError):
>          """Raise an exception if the given condition is not true"""
>          if not cond:
>              if msg is None:
>                  frame = sys._getframe(1)
>                  line = frame.f_lineno
>                  modname = frame.f_globals.get("__name__", "<unknown module>")
>                  msg = f"Condition not met on line {line:d} in {modname!r}"
>              raise exc_type(msg)
>
> Cheers,
> Nick.
>
> P.S. No, I'm not offering to write that PEP myself, I'd just be in
> favour of the idea if someone else were to write it :)
>

I'd prefer (cond, exc_type=RuntimeError, msg=None). For example:

ensure(x != 0, ZeroDivisionError)

ensure(x > 0, IndexError, "list index out of range")

ensure(x != FAIL, msg="failing")

I'm not sure how you'd neatly handle no-args constructors and 
multiple-arguments constructors, tho.


More information about the Python-ideas mailing list