__init__.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. import functools
  2. import threading
  3. import collections
  4. def map0(func, value):
  5. return func(value) if value is not None else value
  6. def single(x):
  7. if len(x) != 1:
  8. raise Exception('Length of {} is not equal to 1'.format(x))
  9. return x[0]
  10. class _Result(object):
  11. pass
  12. def lazy(func):
  13. result = _Result()
  14. lock = threading.Lock()
  15. @functools.wraps(func)
  16. def wrapper(*args):
  17. try:
  18. return result.result
  19. except AttributeError:
  20. with lock:
  21. try:
  22. return result.result
  23. except AttributeError:
  24. result.result = func(*args)
  25. return result.result
  26. return wrapper
  27. def lazy_property(fn):
  28. attr_name = '_lazy_' + fn.__name__
  29. lock = threading.Lock()
  30. @property
  31. def _lazy_property(self):
  32. if hasattr(self, attr_name):
  33. return getattr(self, attr_name)
  34. with lock:
  35. if not hasattr(self, attr_name):
  36. setattr(self, attr_name, fn(self))
  37. return getattr(self, attr_name)
  38. return _lazy_property
  39. class classproperty(object):
  40. def __init__(self, func):
  41. self.func = func
  42. def __get__(self, _, owner):
  43. return self.func(owner)
  44. class lazy_classproperty(object):
  45. def __init__(self, func):
  46. self.func = func
  47. def __get__(self, _, owner):
  48. attr_name = '_lazy_' + self.func.__name__
  49. if not hasattr(owner, attr_name):
  50. setattr(owner, attr_name, self.func(owner))
  51. return getattr(owner, attr_name)
  52. def memoize(limit=0, thread_local=False):
  53. assert limit >= 0
  54. def decorator(func):
  55. memory = {}
  56. lock = threading.Lock()
  57. if limit:
  58. keys = collections.deque()
  59. def get(args):
  60. try:
  61. return memory[args]
  62. except KeyError:
  63. with lock:
  64. if args not in memory:
  65. fargs = args[-1]
  66. memory[args] = func(*fargs)
  67. keys.append(args)
  68. if len(keys) > limit:
  69. del memory[keys.popleft()]
  70. return memory[args]
  71. else:
  72. def get(args):
  73. if args not in memory:
  74. with lock:
  75. if args not in memory:
  76. fargs = args[-1]
  77. memory[args] = func(*fargs)
  78. return memory[args]
  79. if thread_local:
  80. @functools.wraps(func)
  81. def wrapper(*args):
  82. th = threading.current_thread()
  83. return get((th.ident, th.name, args))
  84. else:
  85. @functools.wraps(func)
  86. def wrapper(*args):
  87. return get(('', '', args))
  88. return wrapper
  89. return decorator
  90. # XXX: add test
  91. def compose(*functions):
  92. def compose2(f, g):
  93. return lambda x: f(g(x))
  94. return functools.reduce(compose2, functions, lambda x: x)
  95. class Singleton(type):
  96. _instances = {}
  97. def __call__(cls, *args, **kwargs):
  98. if cls not in cls._instances:
  99. cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
  100. return cls._instances[cls]
  101. def stable_uniq(it):
  102. seen = set()
  103. res = []
  104. for e in it:
  105. if e not in seen:
  106. res.append(e)
  107. seen.add(e)
  108. return res
  109. def first(it):
  110. for d in it:
  111. if d:
  112. return d
  113. def split(data, func):
  114. l, r = [], []
  115. for e in data:
  116. if func(e):
  117. l.append(e)
  118. else:
  119. r.append(e)
  120. return l, r
  121. def flatten_dict(dd, separator='.', prefix=''):
  122. return (
  123. {
  124. prefix + separator + k if prefix else k: v
  125. for kk, vv in dd.items()
  126. for k, v in flatten_dict(vv, separator, kk).items()
  127. }
  128. if isinstance(dd, dict)
  129. else {prefix: dd}
  130. )