
On Sun, Dec 27, 2020 at 1:15 PM Brendan Barnwell <brenbarn@brenbarn.net> wrote:
On 2020-12-26 18:03, Chris Angelico wrote:
On Sun, Dec 27, 2020 at 11:36 AM Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
On 27/12/20 10:15 am, Christopher Barker wrote:
It does seem like ** could be usable with any iterable that returns pairs of objects. However the trick is that when you iterate a dict, you get the keys, not the items, which makes me think that the only thing you should *need* is an items() method that returns an iterable (pf pairs of objects).
It seems to me it would be more fundamental to use iteration to get the keys and indexing to get the corresponding values. You're only relying on dunder methods then.
But that would mean that a lot of iterables would look like mappings when they're not. Consider:
def naive_items(x): ... return [(key, x[key]) for key in x] ... naive_items(range(9, -1, -1)) [(9, 0), (8, 1), (7, 2), (6, 3), (5, 4), (4, 5), (3, 6), (2, 7), (1, 8), (0, 9)]
I don't see that as a major problem. It is no more "surprising" than doing something like list('abc') and getting ['a', 'b', 'c']. If you do {**range(9, -1, -1)} you may get a result that looks strange or isn't useful, but as long as the result is consistent with the protocol, that's fine. Just don't use **-unpacking with ranges if you don't want to.
Perhaps, but that means you can't raise TypeError for anything iterable. Instead, you'd have to raise ValueError, because it could potentially be valid. Are mappings really just iterables with indexing (which most iterables support), or are they distinctly different? Remember, most things iterate over their *values*, but a dict iterates over its *keys*. On the plus side, you COULD convert some objects into sparse lists by basically just dictifying them:
{**range(5)} # with this proposal {0: 0, 1: 1, 2: 2, 3: 3, 4: 4}
But on the downside, you could only do this if they iterate the 'right way', which most iterables won't. It would be MUCH more useful if there were a dedicated way to request the valid keys or items, and use that instead. Then you could convert *any* iterable that way. At the moment, you can create an actual dict from any iterable by enumerating, and that will give the correct items:
def smarter_items(x): ... return list(dict(enumerate(x)).items()) ... smarter_items(range(9, -1, -1)) [(0, 9), (1, 8), (2, 7), (3, 6), (4, 5), (5, 4), (6, 3), (7, 2), (8, 1), (9, 0)] smarter_items(range(10, 20)) [(0, 10), (1, 11), (2, 12), (3, 13), (4, 14), (5, 15), (6, 16), (7, 17), (8, 18), (9, 19)]
If you want to dictify something, that'd be the more normal way to do it, IMO. Instead of something with lots of false positives, wouldn't it be cleaner to have a protocol that specifically returns the equivalent of dict.items()? ChrisA