systypes.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. # -*- coding: utf-8 -*-
  2. #!/usr/bin/env python
  3. import threading
  4. from itertools import chain
  5. from enum import IntEnum as _IntEnum, Enum
  6. from typing import List
  7. def enum(**enums):
  8. return type('Enum', (), enums)
  9. class IntEnum(_IntEnum):
  10. @classmethod
  11. def choices(cls):
  12. return [ _.value for _ in cls.__members__.values() ]
  13. class StrEnum(str, Enum):
  14. @classmethod
  15. def choices(cls):
  16. return [ _.value for _ in cls.__members__.values() ]
  17. class IterConstant(object):
  18. """
  19. 用此类代替枚举的原因在于IDE等工具的可观察性, 一定程度牺牲不可变性
  20. """
  21. @classmethod
  22. def choices(cls):
  23. # type: ()->List[str]
  24. return map(lambda _: getattr(cls, _),
  25. [_ for _ in dir(cls) if not _.startswith('__') and not callable(getattr(cls, _))])
  26. class Singleton(object):
  27. objs = {}
  28. objs_locker = threading.Lock()
  29. def __new__(cls, *args, **kv):
  30. if cls in cls.objs:
  31. return cls.objs[cls]['obj']
  32. cls.objs_locker.acquire()
  33. try:
  34. if cls in cls.objs: ## double check locking
  35. return cls.objs[cls]['obj']
  36. obj = object.__new__(cls)
  37. cls.objs[cls] = {'obj': obj, 'init': False}
  38. setattr(cls, '__init__', cls.decorate_init(cls.__init__))
  39. return cls.objs[cls]['obj']
  40. finally:
  41. cls.objs_locker.release()
  42. @classmethod
  43. def decorate_init(cls, fn):
  44. def init_wrap(*args):
  45. if not cls.objs[cls]['init']:
  46. fn(*args)
  47. cls.objs[cls]['init'] = True
  48. return
  49. return init_wrap
  50. class NoEmptyValueDict(dict):
  51. @staticmethod
  52. def _process_args(mapping = (), **kwargs):
  53. if hasattr(mapping, 'items'):
  54. mapping = getattr(mapping, 'items')()
  55. return ((k, v) for k, v in chain(mapping, getattr(kwargs, 'items')()) if v)
  56. def __setitem__(self, i, y):
  57. if y:
  58. super(NoEmptyValueDict, self).__setitem__(i, y)
  59. def update(self, E = None, **F):
  60. super(NoEmptyValueDict, self).update(self._process_args(E, **F))
  61. def setdefault(self, k, d=None):
  62. if k in self:
  63. return super(NoEmptyValueDict, self).setdefault(k, d)
  64. if not d:
  65. return None
  66. else:
  67. return super(NoEmptyValueDict, self).setdefault(k, d)
  68. class NoInstantiateMeta(type):
  69. def __call__(cls, *args, **kwargs):
  70. raise TypeError("BaseIterConstant class cannot be instantiated.")
  71. class BaseIterConstant(object):
  72. """
  73. 代替IterConstant基类
  74. """
  75. __metaclass__ = NoInstantiateMeta
  76. @classmethod
  77. def choice(cls, call=None):
  78. """
  79. call 表示需要对获取的值执行的方法 比如int、str、float、lambda x: x+1
  80. """
  81. if call and callable(call):
  82. return [call(getattr(cls, attr)) for attr in dir(cls) if not attr.startswith("_") and attr.isupper()]
  83. else:
  84. return [getattr(cls, attr) for attr in dir(cls) if not attr.startswith("_") and attr.isupper()]