Debug Tools
DynamicIterationDict Class Reference
Inheritance diagram for DynamicIterationDict:
Collaboration diagram for DynamicIterationDict:

Public Member Functions

def __init__ (self, initial=None, is_set=False, emquote=False, index=False)
 
def __repr__ (self)
 
def __str__ (self)
 
def __contains__ (self, key)
 
def __len__ (self)
 
def __call__ (self, how_many_times=-1)
 
def __iter__ (self)
 
def __setitem__ (self, key, value)
 
def __getitem__ (self, key)
 
def __delitem__ (self, key)
 
def trim_indexes_sorted (self)
 
def trim_indexes_unsorted (self)
 
def keys (self, how_many_times=-1)
 
def values (self, how_many_times=-1)
 
def items (self, how_many_times=-1)
 
def get_key (self, index)
 
def get_value (self, index)
 
def get_key_value (self, index)
 
def get_iterator (self, target_generation, how_many_times=-1)
 
def not_iterate_over_new_items (self, how_many_times=1)
 
def fromkeys (self, iterable)
 
def append (self, element)
 
def remove (self, element)
 
def add (self, element)
 
def discard (self, element)
 
def copy (self)
 
def clear (self)
 

Public Attributes

 keys_list
 The list with the keys of this collection elements.
 
 values_list
 The list with the elements of this collection.
 
 empty_slots
 List the empty free spots for old items, used globally before the iteration starts.
 
 filled_slots
 List the empty free spots for old items, used globally after the iteration starts with new_items_skip_count
 
 items_dictionary
 A dictionary with the indexes of the elements in this collection.
 
 new_items_skip_count
 Whether the iteration process is allowed to use new items added on the current iteration.
 
 new_items_skip_stack
 A stack of new_items_skip_count which is required when the current iterator is called recursively.
 
 maximum_iterable_index
 Holds the global maximum iterable index used when new_items_skip_count is set.
 

Detailed Description

    A `dict()` like object which allows to dynamically add and remove items while iterating over
    its elements as in `for element in dynamic_set`

    https://wiki.python.org/moin/TimeComplexity
    https://stackoverflow.com/questions/4014621/a-python-class-that-acts-like-dict

Definition at line 139 of file dynamic_iteration.py.

Constructor & Destructor Documentation

◆ __init__()

def __init__ (   self,
  initial = None,
  is_set = False,
  emquote = False,
  index = False 
)
    Fully initializes and create a new dictionary.

    @param `initial` is a dictionary used to initialize it with new values.

Definition at line 148 of file dynamic_iteration.py.

References DynamicIterationDict._is_set.

148  def __init__(self, initial=None, is_set=False, emquote=False, index=False):
149  """
150  Fully initializes and create a new dictionary.
151 
152  @param `initial` is a dictionary used to initialize it with new values.
153  """
154 
155 
156  self._is_set = is_set
157 
158 
159  self.keys_list = list()
160 
161 
162  self.values_list = list()
163 
164 
165  self._emquote_keys = emquote
166 
167 
168  self._add_index = index
169 
170 
171  self.empty_slots = set()
172 
173 
174  self.filled_slots = set()
175 
176 
177  self.items_dictionary = dict()
178 
179 
180  self.new_items_skip_count = 0
181 
182 
183  self.new_items_skip_stack = []
184 
185 
186  self.maximum_iterable_index = [0]
187 
188  if initial:
189 
190  if isinstance( initial, dict ):
191 
192  for key, value in initial.items():
193  self[key] = value
194 
195  else:
196  self.fromkeys( initial )
197 

Member Function Documentation

◆ __call__()

def __call__ (   self,
  how_many_times = -1 
)
    Return a iterable for the keys elements of this collection when calling its object as a
    function call.

    `how_many_times` is for how many iterations it should keep ignoring the new items.

Definition at line 251 of file dynamic_iteration.py.

References DynamicIterationDict.get_iterator(), and DynamicIterationDict.get_key().

251  def __call__(self, how_many_times=-1):
252  """
253  Return a iterable for the keys elements of this collection when calling its object as a
254  function call.
255 
256  `how_many_times` is for how many iterations it should keep ignoring the new items.
257  """
258  return self.get_iterator( self.get_key, how_many_times )
259 
Here is the call graph for this function:

◆ __contains__()

def __contains__ (   self,
  key 
)
    Determines whether this dictionary contains or not a given `key`.

Definition at line 239 of file dynamic_iteration.py.

References DynamicIterationDict.items_dictionary.

239  def __contains__(self, key):
240  """
241  Determines whether this dictionary contains or not a given `key`.
242  """
243  return key in self.items_dictionary
244 

◆ __delitem__()

def __delitem__ (   self,
  key 
)
    Given a `key` deletes if from this dict.

Definition at line 307 of file dynamic_iteration.py.

References DynamicIterationDict.add(), DynamicIterable.empty_slots, DynamicIterationDict.empty_slots, and DynamicIterationDict.items_dictionary.

307  def __delitem__(self, key):
308  """
309  Given a `key` deletes if from this dict.
310  """
311  # log( 1, "key: %s, self: %s", key, self )
312  items_dictionary = self.items_dictionary
313  item_index = items_dictionary[key]
314 
315  self.empty_slots.add( item_index )
316  del items_dictionary[key]
317 
Here is the call graph for this function:

◆ __getitem__()

def __getitem__ (   self,
  key 
)
    Given a `key` returns its existent value.

Definition at line 300 of file dynamic_iteration.py.

References DynamicIterationDict.items_dictionary, and DynamicIterationDict.values_list.

300  def __getitem__(self, key):
301  """
302  Given a `key` returns its existent value.
303  """
304  # log( 1, "index: %s, key: %s", self.items_dictionary[key], key )
305  return self.values_list[self.items_dictionary[key]]
306 

◆ __iter__()

def __iter__ (   self)
    Called by Python automatically when iterating over this set and python wants to start
    the iteration process.

    Why have an __iter__ method in Python?
    https://stackoverflow.com/questions/36681312/why-have-an-iter-method-in-python

Definition at line 260 of file dynamic_iteration.py.

References DynamicIterationDict.get_iterator(), and DynamicIterationDict.get_key().

260  def __iter__(self):
261  """
262  Called by Python automatically when iterating over this set and python wants to start
263  the iteration process.
264 
265  Why have an __iter__ method in Python?
266  https://stackoverflow.com/questions/36681312/why-have-an-iter-method-in-python
267  """
268  return self.get_iterator( self.get_key )
269 
Here is the call graph for this function:

◆ __len__()

def __len__ (   self)
    Return the total length of this set.

Definition at line 245 of file dynamic_iteration.py.

References DynamicIterationDict.items_dictionary.

245  def __len__(self):
246  """
247  Return the total length of this set.
248  """
249  return len( self.items_dictionary )
250 

◆ __repr__()

def __repr__ (   self)
    Return a full representation of all public attributes of this object set state for
    debugging purposes.

Definition at line 198 of file dynamic_iteration.py.

Referenced by LockableType.__setattr__().

198  def __repr__(self):
199  """
200  Return a full representation of all public attributes of this object set state for
201  debugging purposes.
202  """
203  return get_representation( self )
204 
Here is the caller graph for this function:

◆ __setitem__()

def __setitem__ (   self,
  key,
  value 
)
    Given a `key` and `item` add it to this dictionary as a non yet iterated item, replacing
    the existent value. It a iteration is running, and the item was already iterated, then
    it will be updated on the `niterated_items` dict.

Definition at line 270 of file dynamic_iteration.py.

References DynamicIterationDict.add(), DynamicIterationDict.append(), DynamicIterable.empty_slots, DynamicIterationDict.empty_slots, DynamicIterable.filled_slots, DynamicIterationDict.filled_slots, DynamicIterationDict.items_dictionary, DynamicIterationDict.keys_list, DynamicIterationDict.new_items_skip_count, and DynamicIterationDict.values_list.

270  def __setitem__(self, key, value):
271  """
272  Given a `key` and `item` add it to this dictionary as a non yet iterated item, replacing
273  the existent value. It a iteration is running, and the item was already iterated, then
274  it will be updated on the `niterated_items` dict.
275  """
276  items_dictionary = self.items_dictionary
277 
278  if key in items_dictionary:
279  item_index = items_dictionary[key]
280  self.values_list[item_index] = value
281 
282  else:
283  empty_slots = self.empty_slots
284  values_list = self.values_list
285 
286  if empty_slots and self.new_items_skip_count > 0:
287  free_slot = empty_slots.pop()
288  self.filled_slots.add( free_slot )
289 
290  values_list[free_slot] = value
291  self.keys_list[free_slot] = key
292 
293  else:
294  free_slot = len( values_list )
295  values_list.append( value )
296  self.keys_list.append( key )
297 
298  self.items_dictionary[key] = free_slot
299 
Here is the call graph for this function:

◆ __str__()

def __str__ (   self)
    Return a nice string representation of this collection.

Definition at line 205 of file dynamic_iteration.py.

References DynamicIterationDict._add_index, DynamicIterationDict._emquote_keys, DynamicIterationDict._is_set, DynamicIterable.empty_slots, DynamicIterationDict.empty_slots, DynamicIterationDict.get_key(), DynamicIterationDict.keys(), DynamicIterationDict.keys_list, and DynamicIterationDict.values_list.

Referenced by LockableType.__repr__().

205  def __str__(self):
206  """
207  Return a nice string representation of this collection.
208  """
209  keys_list = self.keys_list
210  empty_slots = self.empty_slots
211  representation = []
212 
213  if self._emquote_keys:
214  get_key = lambda: emquote_string( key )
215 
216  else:
217  get_key = lambda: key
218 
219  if self._add_index:
220  get_index = lambda: "{}, {}".format( get_key(), index )
221 
222  else:
223  get_index = get_key
224 
225  if self._is_set:
226  return str( self.keys() )
227 
228  else:
229  values_list = self.values_list
230 
231  for index in range( 0, len( keys_list ) ):
232 
233  if index not in empty_slots:
234  key = keys_list[index]
235  representation.append( "%s: %s" % ( get_index(), values_list[index] ) )
236 
237  return "{%s}" % ", ".join( representation )
238 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ add()

def add (   self,
  element 
)
    Add a new element to the end of the list.

Definition at line 468 of file dynamic_iteration.py.

Referenced by DynamicIterationDict.__delitem__(), and DynamicIterationDict.__setitem__().

468  def add(self, element):
469  """
470  Add a new element to the end of the list.
471  """
472  self[element] = None
473 
Here is the caller graph for this function:

◆ append()

def append (   self,
  element 
)
    Add a new element to the end of the list.

Definition at line 456 of file dynamic_iteration.py.

Referenced by DynamicIterationDict.__setitem__(), and DynamicIterationDict.not_iterate_over_new_items().

456  def append(self, element):
457  """
458  Add a new element to the end of the list.
459  """
460  self[element] = None
461 
Here is the caller graph for this function:

◆ clear()

def clear (   self)
    Remove all items from this dict.

Definition at line 489 of file dynamic_iteration.py.

References DynamicIterable.empty_slots, DynamicIterationDict.empty_slots, DynamicIterable.filled_slots, DynamicIterationDict.filled_slots, DynamicIterationDict.items_dictionary, DynamicIterationDict.keys_list, and DynamicIterationDict.values_list.

Referenced by SleepEvent.sleep(), and DynamicIterationDict.trim_indexes_sorted().

489  def clear(self):
490  """
491  Remove all items from this dict.
492  """
493  self.empty_slots.clear()
494  self.filled_slots.clear()
495 
496  self.keys_list.clear()
497  self.values_list.clear()
498  self.items_dictionary.clear()
499 
500 
Here is the caller graph for this function:

◆ copy()

def copy (   self)
    Return a deep copy of this collection.

Definition at line 483 of file dynamic_iteration.py.

483  def copy(self):
484  """
485  Return a deep copy of this collection.
486  """
487  return copy.deepcopy( self )
488 

◆ discard()

def discard (   self,
  element 
)
    Remove new `element` anywhere in the container.

Definition at line 474 of file dynamic_iteration.py.

474  def discard(self, element):
475  """
476  Remove new `element` anywhere in the container.
477  """
478  try:
479  del self[element]
480  except KeyError:
481  pass
482 

◆ fromkeys()

def fromkeys (   self,
  iterable 
)
    Initialize a dictionary with None default value, acting like a indexed set.

Definition at line 448 of file dynamic_iteration.py.

448  def fromkeys(self, iterable):
449  """
450  Initialize a dictionary with None default value, acting like a indexed set.
451  """
452 
453  for key in iterable:
454  self[key] = None
455 

◆ get_iterator()

def get_iterator (   self,
  target_generation,
  how_many_times = -1 
)
    Get fully configured iterable given the getter `target_generation(index)` function.

    `how_many_times` is for how many iterations it should keep ignoring the new items.

Definition at line 408 of file dynamic_iteration.py.

References DynamicIterable.empty_slots, DynamicIterationDict.empty_slots, DynamicIterable.filled_slots, DynamicIterationDict.filled_slots, DynamicIterationDict.items_dictionary, DynamicIterationDict.maximum_iterable_index, DynamicIterationDict.new_items_skip_count, DynamicIterationDict.new_items_skip_stack, and DynamicIterationDict.not_iterate_over_new_items().

Referenced by DynamicIterationDict.__call__(), DynamicIterationDict.__iter__(), DynamicIterationDict.items(), DynamicIterationDict.keys(), and DynamicIterationDict.values().

408  def get_iterator(self, target_generation, how_many_times=-1):
409  """
410  Get fully configured iterable given the getter `target_generation(index)` function.
411 
412  `how_many_times` is for how many iterations it should keep ignoring the new items.
413  """
414  self.new_items_skip_count -= 1
415 
416  # When the current sequence is exhausted, search for an old one
417  if not self.new_items_skip_count > 0:
418 
419  # Unwind the stack until a valid item is found
420  if self.new_items_skip_stack:
421  self.new_items_skip_count = self.new_items_skip_stack.pop()
422 
423  self.not_iterate_over_new_items( how_many_times )
424 
425  if self.new_items_skip_count > 0:
426  return DynamicIterable( self.items_dictionary, target_generation, self.empty_slots, self.maximum_iterable_index, self.filled_slots )
427 
428  return DynamicIterable( self.items_dictionary, target_generation, self.empty_slots )
429 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_key()

def get_key (   self,
  index 
)
    Given a `index` returns its corresponding key.

Definition at line 390 of file dynamic_iteration.py.

References DynamicIterationDict.keys_list.

Referenced by DynamicIterationDict.__call__(), DynamicIterationDict.__iter__(), DynamicIterationDict.__str__(), and DynamicIterationDict.keys().

390  def get_key(self, index):
391  """
392  Given a `index` returns its corresponding key.
393  """
394  return self.keys_list[index]
395 
Here is the caller graph for this function:

◆ get_key_value()

def get_key_value (   self,
  index 
)
    Given a `index` returns its corresponding (key, value) pair.

Definition at line 402 of file dynamic_iteration.py.

References DynamicIterationDict.keys_list, and DynamicIterationDict.values_list.

Referenced by DynamicIterationDict.items().

402  def get_key_value(self, index):
403  """
404  Given a `index` returns its corresponding (key, value) pair.
405  """
406  return ( self.keys_list[index], self.values_list[index] )
407 
Here is the caller graph for this function:

◆ get_value()

def get_value (   self,
  index 
)
    Given a `index` returns its corresponding value.

Definition at line 396 of file dynamic_iteration.py.

References DynamicIterationDict.values_list.

Referenced by DynamicIterationDict.values().

396  def get_value(self, index):
397  """
398  Given a `index` returns its corresponding value.
399  """
400  return self.values_list[index]
401 
Here is the caller graph for this function:

◆ items()

def items (   self,
  how_many_times = -1 
)
    Return a DynamicIterable over the (key, value) stored in this collection.

    `how_many_times` is for how many iterations it should keep ignoring the new items.

Definition at line 382 of file dynamic_iteration.py.

References DynamicIterationDict.get_iterator(), and DynamicIterationDict.get_key_value().

382  def items(self, how_many_times=-1):
383  """
384  Return a DynamicIterable over the (key, value) stored in this collection.
385 
386  `how_many_times` is for how many iterations it should keep ignoring the new items.
387  """
388  return self.get_iterator( self.get_key_value, how_many_times )
389 
Here is the call graph for this function:

◆ keys()

def keys (   self,
  how_many_times = -1 
)
    Return a DynamicIterable over the keys stored in this collection.

    `how_many_times` is for how many iterations it should keep ignoring the new items.

Definition at line 366 of file dynamic_iteration.py.

References DynamicIterationDict.get_iterator(), and DynamicIterationDict.get_key().

Referenced by DynamicIterationDict.__str__().

366  def keys(self, how_many_times=-1):
367  """
368  Return a DynamicIterable over the keys stored in this collection.
369 
370  `how_many_times` is for how many iterations it should keep ignoring the new items.
371  """
372  return self.get_iterator( self.get_key, how_many_times )
373 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ not_iterate_over_new_items()

def not_iterate_over_new_items (   self,
  how_many_times = 1 
)
    If called before start iterating over this dictionary, it will not iterate over the
    new keys added until the current iteration is over.

    `how_many_times` is for how many iterations it should keep ignoring the new items.

Definition at line 430 of file dynamic_iteration.py.

References DynamicIterationDict.append(), DynamicIterable.filled_slots, DynamicIterationDict.filled_slots, DynamicIterationDict.keys_list, DynamicIterationDict.maximum_iterable_index, DynamicIterationDict.new_items_skip_count, and DynamicIterationDict.new_items_skip_stack.

Referenced by DynamicIterationDict.get_iterator().

430  def not_iterate_over_new_items(self, how_many_times=1):
431  """
432  If called before start iterating over this dictionary, it will not iterate over the
433  new keys added until the current iteration is over.
434 
435  `how_many_times` is for how many iterations it should keep ignoring the new items.
436  """
437 
438  if how_many_times > 0:
439 
440  if self.new_items_skip_count > 0:
441  self.new_items_skip_stack.append( self.new_items_skip_count )
442 
443  self.filled_slots = set()
444  self.new_items_skip_count = how_many_times
445  self.maximum_iterable_index = [0]
446  self.maximum_iterable_index[0] = len( self.keys_list )
447 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ remove()

def remove (   self,
  element 
)
    Remove new `element` anywhere in the container.

Definition at line 462 of file dynamic_iteration.py.

462  def remove(self, element):
463  """
464  Remove new `element` anywhere in the container.
465  """
466  del self[element]
467 

◆ trim_indexes_sorted()

def trim_indexes_sorted (   self)
    Fix the the outdated indexes on the internal lists after their dictionary removal,
    keeping the items original ordering O(n).

Definition at line 318 of file dynamic_iteration.py.

References DynamicIterationDict.clear(), DynamicIterable.empty_slots, DynamicIterationDict.empty_slots, DynamicIterationDict.items_dictionary, DynamicIterationDict.keys_list, and DynamicIterationDict.values_list.

318  def trim_indexes_sorted(self):
319  """
320  Fix the the outdated indexes on the internal lists after their dictionary removal,
321  keeping the items original ordering O(n).
322  """
323  new_index = -1
324  clean_keys = []
325  clean_values = []
326 
327  values_list = self.values_list
328  items_dictionary = self.items_dictionary
329 
330  for key, value_index in items_dictionary.items():
331  new_index += 1
332  items_dictionary[key] = new_index
333  clean_keys.append( key )
334  clean_values.append( values_list[value_index] )
335 
336  self.empty_slots.clear()
337  self.keys_list = clean_keys
338  self.values_list = clean_values
339 
Here is the call graph for this function:

◆ trim_indexes_unsorted()

def trim_indexes_unsorted (   self)
    Fix the the outdated indexes on the internal lists after their dictionary removal.
    keeping the items original ordering O(k), where `k` is length of `self.empty_slots`.

Definition at line 340 of file dynamic_iteration.py.

References DynamicIterable.empty_slots, DynamicIterationDict.empty_slots, DynamicIterationDict.items_dictionary, DynamicIterationDict.keys_list, and DynamicIterationDict.values_list.

340  def trim_indexes_unsorted(self):
341  """
342  Fix the the outdated indexes on the internal lists after their dictionary removal.
343  keeping the items original ordering O(k), where `k` is length of `self.empty_slots`.
344  """
345  keys_list = self.keys_list
346  values_list = self.values_list
347  empty_slots = self.empty_slots
348  last_slot = -1
349 
350  while empty_slots:
351  empty_slot = empty_slots.pop()
352  list_length = len( keys_list )
353  key = keys_list.pop()
354 
355  keys_list[empty_slot] = key
356  values_list[empty_slot] = values_list.pop()
357  self.items_dictionary[key] = empty_slot
358 
359  if last_slot >= list_length:
360  last_slot = last_slot
361 
362  if last_slot > -1:
363  del keys_list[last_slot:]
364  del values_list[last_slot:]
365 

◆ values()

def values (   self,
  how_many_times = -1 
)
    Return a DynamicIterable over the values stored in this collection.

    `how_many_times` is for how many iterations it should keep ignoring the new items.

Definition at line 374 of file dynamic_iteration.py.

References DynamicIterationDict.get_iterator(), and DynamicIterationDict.get_value().

374  def values(self, how_many_times=-1):
375  """
376  Return a DynamicIterable over the values stored in this collection.
377 
378  `how_many_times` is for how many iterations it should keep ignoring the new items.
379  """
380  return self.get_iterator( self.get_value, how_many_times )
381 
Here is the call graph for this function:

The documentation for this class was generated from the following file: