[Python-Dev] PEP 409 - final?

Guido van Rossum guido at python.org
Wed Feb 1 21:07:06 CET 2012


On Wed, Feb 1, 2012 at 10:48 AM, Ethan Furman <ethan at stoneleaf.us> wrote:
> Guido van Rossum wrote:
>>
>> Hm... Reading this draft, I like the idea of using "raise X from
>> None", but I still have one quibble. It seems the from clause sets
>> __cause__, and __cause__ can indicate three things: (1) print
>> __cause__ (explicitly set), (2) print __context__ (default), (3) print
>> neither (raise X from None). For (1), __cause__ must of course be a
>> traceback object.
>
>
> Actually, for (1) __cause__ is an exception object, not a traceback.

Ah, sorry. I'm not as detail-oriented as I was. :-)

>> The PEP currently proposes to use two special
>> values: False for (2), None for (3). To me, this has a pretty strong
>> code smell, and I don't want this pattern to be enshrined in a PEP as
>> an example for all to follow. (And I also don't like "do as I say,
>> don't do as I do." :-)
>
>
> My apologies for my ignorance, but is the code smell because both False and
> None evaluate to bool(False)?

That's part of it, but the other part is that the type of __context__
is now truly dynamic. I often *think* of variables as having some
static type, e.g. "integer" or "Foo instance", and for most Foo
instances I consider None an acceptable value (since that's how
pointer types work in most static languages). But the type of
__context__ you're proposing is now a union of exception and bool,
except that the bool can only be False.

> I suppose we could use True for (2) to
> indicate that __context__ should be printed, leaving None for (3)... but
> having __context__ at None and __cause__ at True could certainly be
> confusing (the default case when no chaining is in effect).

It seems you really need a marker object. I'd be fine with using some
other opaque marker -- IMO that's much better than using False but
disallowing True.

>> Can we think of a different special value to distinguish between (2)
>> and (3)? Ideally one that doesn't change the nice "from None" idiom,
>> which I actually like as a way to spell this.
>
>
> How about this:
>
>
> Exception Life Cycle
> ====================
>
>
> Stage 1 - brand new exception
> -----------------------------
>
> raise ValueError()
>
> * __context__ is None
> * __cause__ is None
>
>
> Stage 2 - exception caught, exception raised
> --------------------------------------------
>
> try:
>   raise ValueError()
> except Exception:
>   raise CustomError()
>
> * __context__ is previous exception
> * __cause__ is True
>
>
> Stage 3 - exception raised from [exception | None]
> --------------------------------------------------
>
> try:
>   raise ValueError()
> except Exception:
>   raise CustomError() from [OtherException | None]
>
> * __context__ is previous exception
> * __cause__ is [OtherException | None]

No, this has the same code smell for me. See above.

>> Sorry that life isn't easier,
>
>
> Where would be the fun without the challenge?

+1 :-)

-- 
--Guido van Rossum (python.org/~guido)


More information about the Python-Dev mailing list