__init__.py 3.7 KB

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