[Python-ideas] A better (simpler) approach to PEP 505

David Mertz mertz at gnosis.cx
Mon Jul 23 13:55:48 EDT 2018


On Mon, Jul 23, 2018 at 1:28 PM Steven D'Aprano <steve at pearwood.info> wrote:

> There's the first bug right there. foo.bar.blim ought to raise
> AttributeError, since there is no blim attribute defined on foo.bar.
>

Note my observation that this is deliberately different semantics.  I want
to solve the underlying need, not simply emulate the less useful semantics
of PEP 505.  But those same semantics COULD be perfectly well emulated with
a similar class.


> > In [8]: NoneAware(foo).bar.blim.unbox()
> > In [9]: NoneAware(foo).bar.baz.blat.unbox()
> > Out[9]: 42
>
> How many bugs will be caused by people forgetting to unbox when they're
> done?
>

Far fewer and far more easily caught.  When the object you get wherever the
real failure happens is ` <none_aware.NoneAware at 0x11156a748>` or the
like, the source of the problem become dead obvious.  Having `None`
somewhere unexpected is much more mysterious and difficult to diagnose.

That said, NoneAware is the wrong name for the class I wrote.  Maybe
GreedyAccess would be a better name.  Perhaps I'll make slightly less toy
implementations of an actual NoneCoalesce and GreedyAccess class and post
in this thread and/or on PyPI.

It does look like PyMaybe does much of what I'm thinking of.  I didn't
think my toy was the first or best implementation.


> But we aren't entering such a world, at least not in PEP 505. Attribute
> access can fail.



> spam.eggs = 42

spam?.eggs?.upper



> is still going to raise AttributeError, because eggs is not None, it is an
> int, and ints don't have an attribute "upper".


True enough.  But it's extremely difficult to imagine a real-world case
where those particular semantics are actually particularly useful.  I guess
my revulsion at the syntax blinded me to the fact that the semantics are
actually pretty bad on their own.


> How does your class implement short-circuit behaviour?
>

You mean if we want something like this?

    favorite = GreedyAccess(cfg,
sentinel=ExpensiveLookup()).user.profile.food.unbox()

It doesn't.  Something else (like PyMaybe) could defer the computation
using a lambda or other means.  My toy code doesn't do that.  We could also
avoid the visible lambda by doing an 'iscallable(sentinel)' and only
calling it if it turns out to be needed, but that might be too magical.
E.g.:

    # If we fail, favorite = ExpensiveLookup(), by magic
    favorite = GreedyAccess(cfg,
sentinel=ExpensiveLookup).user.profile.food.unbox()

So we don't like operators like ?? because its too cryptic, but you're
> happy to have one-character class and property names.
>

No, I'm not happy with that.  I was just pointing out that code golf is
possible for someone who really wants it.  I'm happy to spend a few
characters for readability.  But one COULD write:

    from nested import GreedyAccess as G
    G._ = G.unbox


> What happens if you have an attribute that happens to be
> called "unbox" in your attribute look-up chain?
>

Don't use this class and/or modify the API slightly? This is getting
trite.  My 5 minute code isn't a final proposal, just a way of seeing a
napkin-sketch of a better approach.

-- 
Keeping medicines from the bloodstreams of the sick; food
from the bellies of the hungry; books from the hands of the
uneducated; technology from the underdeveloped; and putting
advocates of freedom in prisons.  Intellectual property is
to the 21st century what the slave trade was to the 16th.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20180723/0df2cec7/attachment-0001.html>


More information about the Python-ideas mailing list