
On Tue, Jun 30, 2020 at 11:10:20AM +0900, Inada Naoki wrote:
On Mon, Jun 29, 2020 at 9:12 PM Hans Ginzel <hans@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