On Wed, Jul 1, 2020 at 12:03 PM Steven D'Aprano <steve@pearwood.info> wrote:
On Mon, Jun 29, 2020 at 06:42:37PM +0100, Stestagg wrote:

> One simple example of where this is surprising is in the following:
>
>     >>> random.choice({'a': 1,}.keys())
>     TypeError: 'dict_keys' object is not subscriptable

I don't know why you think that is surprising. It doesn't surprise me in
the least.


I think it's surprising, because I'm on a channel for python help, and a junior python dev asked about why their code wasn't working, and me and another senior python developer were surprised about the behaviour (Things are more surprising when you're looking at other people's code)
 

> Several times now, I've had the need to 'just get any key/value' from a
> large dictionary.  I usually try first to run `var.keys()[0]` only to be
> told that I'm not allowed to do this,

And you needed to be told several times before you learned that dicts,
and dict views, are not sequences?

I've spent vastly more of my professional career developing in python environments where such code worked (python versions < 3).  The fact that one of the many types of ordered sequence containers in python doesn't support numeric indexing seems like a reasonable thing to forget, especially when such containers are a relatively new addition to the language, and are encountered infrequently.  Your wording here sounds like this is something I should feel shame about?

Hopefully if this proposed change is made, then dict views, which are, after all, iterable ordered containers, can be considered Sequences again.
 

> and instead have to ask python to
> make a copy of this datastructure with a different type, just so I can
> perform the index operation.

That's a hint that the technique you are using to extract a key may be a
poor choice.

There are many ways to do this, it's unfortunate that the most natural seeming method doesn't currently work (hence the proposed change)
 

If you need to remove the key from the dict as well, use the popitem
method.

I typically don't
 

If you don't need to remove it, I think the easiest way would be to use
a helper function:

    def get(obj):
        return next(iter(obj))

which will work on dicts, dict views, sets, frozensets, strings, bytes,
lists, and any collection that supports iteration.

That's a more powerful technique than requiring subscripting because
it will work on sets as well, and it avoids expensive copying
operations.

The downside of this is that repeated calls on the same object will
return the same element each time, but then your attempt with indexing
will have the same problem.

> Another use-cases is doing variations of reduce() over dictionaries, where
> getting an initial value from the dict, and then performing operations over
> the remaining items is much simpler to do with indexing on the views.

reduce has nothing to do with indexing, only iteration, so we can
already use reduce on dicts.

    py> from functools import reduce
    py> d = {3: 'a', 5: 'b', 2: 'c'}
    py> reduce(lambda a,b: (min(a[0], b[0]), a[1]+b[1]), d.items())
    (2, 'abc')

I'm aware that the `reduce` function exists, and how it works.  My wording here was meant to (somewhat implicitly, I accept, by mentioning `variations`) imply that there are situations where reduce isn't ideal.  Often it's a case where the reduce operation is more complex than a simple lambda supports, and where adding a separate function (or nested function) leads to less clear code.  In these cases, a simple addition to the interface of an ordered container would help improve the readability of the implementation.
 

In case that's not clear (reduce often is not :-) that returns the
smallest key with the concatenation of all the values.



--
Steven
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-leave@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/MBCV76GQ2IWFERRUUHPMMPEWFC6LNFIQ/
Code of Conduct: http://python.org/psf/codeofconduct/