On Tue, Jun 30, 2020 at 11:10:20AM +0900, Inada Naoki wrote:
> On Mon, Jun 29, 2020 at 9:12 PM Hans Ginzel <h...@matfyz.cz> wrote:

> > What are the reasons, why object dict.items() is not subscriptable – 
> > dict.items()[0]?
> 
> Because dict is optimized for random access by key and iteration, but not for
> random access by index.

But we're not talking about *dict*, we're talking about dict.items which 
returns a set-like object:

    py> from collections.abc import Set
    py> isinstance({}.items(), Set)
    True

So dict.items isn't subscriptable because it's an unordered set, not a 
sequence.

>     for i in range(len(d)):
>         do(d.items()[i])  # if dict_items supports index access.
> 
> sample 1 is O(n) where n = len(d), but sample 2 is O(n^2).
> 
> By not supporting index access, dict_items prevents to write such
> inefficient code.

I don't think that this is a compelling or strong argument. We can write 
inefficient code because dicts do *not* support index access:

    for i in range(len(d)):
        for j,item in enumerate(d.items()):
            if j == i:
                do(item)

I guess that adding index read access to dicts could be done, perhaps 
with a method:

    d.getitem(3)  # Returns (key, value)

and I don't think that would be expensive. My recollection is that 
internally dicts have, or had, an internal array of keys. So it could be 
a constant time operation to look up the key by index.

We could allow setitem too:

    d.setitem(3) = value

At worst, this would be O(N), which isn't too bad. There are many other 
O(N) operations in Python, such as list.index, str.upper, etc and we 
trust people to use them appropriately, or at least for small N.

I recently wrote O(N**3) code and don't care. I'm never going to need 
it for N greater than about 10, and usually more like 2, 3, or 4, so it 
will be fast enough for my needs.

This is easy enough to solve with an augmented dict. A sketch of a 
possible solution:

    class IndexableDict(dict):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self._items = {i: key for i, key in enumerate(self.keys())

        def getitem(self, i):
            key = self._items[i]
            return (key, self[key])

Overload the other methods as needed.

But even if we could do these efficiently, who would use them? If you 
need this for a table, you probably need to support insertion and 
deletion as well, maybe slices, and you probably need both columns and 
rows, so I really don't think that dict is the right place for this.

I think people who need this functionality should look at other data 
structures, optimized for what you need, not try to force dict to be a 
second-class table. Not every data structure should be forced into 
dicts.

But if a simple indexable dict is all you need, try writing a subclass. 
If you can find good uses for it, propose it to be added to the 
collections module. I would support that.


-- 
Steven
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@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/44LD4SI7SVATA52ZBLR4AIUHOQZKCRAR/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to