Experimental Discord bot written in Python
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

rscollections.py 4.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. """
  2. Subclasses of list, set, and dict with maximum sizes.
  3. """
  4. class BoundList(list):
  5. """
  6. Subclass of `list` that enforces a maximum size.
  7. If the number of elements following a mutating operation exceeds
  8. `self.max_element_count`, then each element will be tested for its "age,"
  9. and the "oldest" elements will be removed until the total size is back
  10. within the limit. "Age" is determined via a provided lambda function. It is
  11. a value with arbitrary numeric value that is used comparitively to find
  12. the element with the smallest value. If no `age_test` is provided, the
  13. default is to remove elem 0.
  14. The age lambda takes two arguments: the element index and the element value.
  15. It must return an int or float.
  16. `self.age_test` and `self.max_element_count` can be modified at runtime,
  17. however elements will only be discarded following the next mutating operation.
  18. """
  19. def __init__(self, max_element_count = 10, age_test = (lambda index, elem: index), *args, **kwargs):
  20. super().__init__(*args, **kwargs)
  21. self.age_test = age_test
  22. self.max_element_count = max_element_count
  23. def __cull_old_elements(self):
  24. while len(self) > self.max_element_count:
  25. oldest_age = None
  26. oldest_index = -1
  27. for i in range(len(self)):
  28. elem = self[i]
  29. age = self.age_test(i, elem)
  30. if oldest_age is None or age < oldest_age:
  31. oldest_age = age
  32. oldest_index = i
  33. self.pop(oldest_index)
  34. # Passthrough methods
  35. def __add__(self, *args):
  36. ret_val = super().__add__(*args)
  37. self.__cull_old_elements()
  38. return ret_val
  39. def __iadd__(self, *args):
  40. ret_val = super().__iadd__(*args)
  41. self.__cull_old_elements()
  42. return ret_val
  43. def append(self, *args):
  44. ret_val = super().append(*args)
  45. self.__cull_old_elements()
  46. return ret_val
  47. def copy(self):
  48. return BoundList(self.max_element_count, self.age_test, super())
  49. def extend(self, *args):
  50. ret_val = super().extend(*args)
  51. self.__cull_old_elements()
  52. return ret_val
  53. def insert(self, *args):
  54. ret_val = super().insert(*args)
  55. self.__cull_old_elements()
  56. return ret_val
  57. class BoundSet(set):
  58. """
  59. Subclass of `set` that enforces a maximum size.
  60. Same behavior as `BoundList`.
  61. `age_test` lambda function takes one argument, the element value.
  62. """
  63. def __init__(self, max_element_count = 10, age_test = (lambda elem: float(elem)), *args, **kwargs):
  64. super().__init__(*args, **kwargs)
  65. self.age_test = age_test
  66. self.max_element_count = max_element_count
  67. def __cull_old_elements(self):
  68. while len(self) > self.max_element_count:
  69. oldest_age = None
  70. oldest_elem = None
  71. for elem in self:
  72. age = self.age_test(elem)
  73. if oldest_age is None or age < oldest_age:
  74. oldest_age = age
  75. oldest_elem = elem
  76. self.remove(oldest_elem)
  77. def add(self, *args):
  78. ret_val = super().add(*args)
  79. self.__cull_old_elements()
  80. return ret_val
  81. def copy(self):
  82. return BoundSet(self.max_element_count, self.age_test, super())
  83. def update(self, *args):
  84. ret_val = super().update(*args)
  85. self.__cull_old_elements()
  86. return ret_val
  87. class BoundDict(dict):
  88. """
  89. Subclass of `dict` that enforces a maximum size.
  90. Same behavior as `BoundList`.
  91. `age_test` lambda takes two arguments: the key and the value of a pair.
  92. """
  93. def __init__(self, max_element_count = 10, age_test = (lambda key, value: float(key)), *args, **kwargs):
  94. super().__init__(*args, **kwargs)
  95. self.age_test = age_test
  96. self.max_element_count = max_element_count
  97. def __cull_old_elements(self):
  98. while len(self) > self.max_element_count:
  99. oldest_age = None
  100. oldest_key = None
  101. for key, value in self.items():
  102. age = self.age_test(key, value)
  103. if oldest_age is None or age < oldest_age:
  104. oldest_age = age
  105. oldest_key = key
  106. del self[oldest_key]
  107. def __ior__(self, *args):
  108. ret_val = super().__ior__(*args)
  109. self.__cull_old_elements()
  110. return ret_val
  111. def __setitem__(self, *args):
  112. super().__setitem__(*args)
  113. self.__cull_old_elements()
  114. def copy(self):
  115. return BoundDict(self.max_element_count, self.age_test, super())
  116. @classmethod
  117. def fromkeys(cls, iter, value=None):
  118. raise RuntimeError('fromkeys not available')
  119. def update(self, *args):
  120. ret_val = super().update(*args)
  121. self.__cull_old_elements()
  122. return ret_val