>>
Code: Select all
class SideDict(MutableMapping, dict): # isinstance(obj, (MutableMapping, dict)) should return True
"""
The purpose of this special dict is to side-attach another dict. A key
and its value from main dict are preferred over same key in the
side-dict. If only a key is not present in main dict, then it is used
from the side-dict.
"""
# The starting SideDict instance will have side_dict=None, a subsequent
# SideDict instance can use the first instance as its side_dict.
def __init__(self, data, side_dict: SideDict | None):
self._store = dict(data)
self._side_dict = side_dict
# Also other stuff
# Also implements __bool__, __contains__, __delitem__, __eq__, __getitem__,
# __missing__, __or__, __setitem__ and others.
def __iter__(self):
self._iter_keys_seen = []
self._iter = self._store.__iter__()
return self
def __next__(self):
# (Just a summary of the code as it is somewhat complex and large.
# The logic seems to be working fine.)
# - First run self._iterator.__next__(). All keys are appended to
# self._iter_keys_seen.
# - The moment StopIteration exception is raised, silence it and
# change iterator to self._side_dict.__iter__().
# - If a key in this iterator is already in self._iter_keys_seen (i.e.
# in self._store), then skip and go to next key.
# - Else return it and also add it to self._iter_keys_seen.
# - If StopIteration is raised now, don't silence it.
def __len__(self):
return len([k for k in self]) # Its not the most efficient, but
# I don't know any other way.
sd_0 = SideDict(data=..., side_dict=None)
sd_1 = SideDict(data=..., side_dict=sd_0)
sd_2 = SideDict(data=..., side_dict=sd_1)
print(len(sd_0), len(sd_1), len(sd_2)) # all work fine
print(list(sd_0)) # ! Here is the problem, shows empty list `[]` !
< /code>
Beim Einlegen von Print () < /code> s, hier ist das, was ich beobachtet habe: < /p>
[*]list()
Code: Select all
[k for k in self]
[*] gefolgt von OBJ .__ Weiter __ () Mehrfach wie es iteriert, wenn obj._store und obj._side_dict . Stopitation , Listen-Verständnis in obj .__ len __ () endet.
Hier beginnt das Problem. list () scheint obj .__ als nächstes __ () unmittelbar nach Ende der Beendigung von obj .__ len __ () zu sein, und es trifft erneut Stopitation . Es gibt keinen obj .__ iter __ () . Und so ist das Endergebnis eine leere Liste! Mein __len __ () verwendet selbst einen Iterator, so dass die beiden denselben Iterator verwenden. Und dann wird dieser Iterator in obj .__ len __ () konsumiert, und für die äußere Liste () ist nichts mehr zu konsumieren. Bitte korrigieren Sie mich, wenn ich falsch liege. Die bessere Lösung
~ 6x schneller als Lösung 2 für die Liste (Side_dict_with_5_items)
Code: Select all
class SideDict(...):
def __iter__(self):
yield from self._store
if self._side_dict is not None:
for key in self._side_dict :
if key not in self._store:
yield key
# Removed __next__(...), all other stuff remains the same
< /code>
[b] 2. Eine andere Arbeitslösung [/b]
Nur für das Konzept
class SideDict(...):
def __iter__(self):
return SideDictIterator(self)
# Removed __next__(...), all other stuff remains the same
class SideDictIterator:
def __init__(self, side_dict: SideDict):
self._side_dict = side_dict
self._iter_keys_seen = []
self._iter = self._side_dict._store.__iter__()
def __iter__(self):
return self
def __next__(self):
# Exactly the same stuff that was in SideDict.__next__(),
# except using self._side_dict instead of self