# -*- coding: utf-8 -*- #!/usr/bin/env python import threading from itertools import chain from enum import IntEnum as _IntEnum, Enum from typing import List def enum(**enums): return type('Enum', (), enums) class IntEnum(_IntEnum): @classmethod def choices(cls): return [ _.value for _ in cls.__members__.values() ] class StrEnum(str, Enum): @classmethod def choices(cls): return [ _.value for _ in cls.__members__.values() ] class IterConstant(object): """ 用此类代替枚举的原因在于IDE等工具的可观察性, 一定程度牺牲不可变性 """ @classmethod def choices(cls): # type: ()->List[str] return map(lambda _: getattr(cls, _), [_ for _ in dir(cls) if not _.startswith('__') and not callable(getattr(cls, _))]) class Singleton(object): objs = {} objs_locker = threading.Lock() def __new__(cls, *args, **kv): if cls in cls.objs: return cls.objs[cls]['obj'] cls.objs_locker.acquire() try: if cls in cls.objs: ## double check locking return cls.objs[cls]['obj'] obj = object.__new__(cls) cls.objs[cls] = {'obj': obj, 'init': False} setattr(cls, '__init__', cls.decorate_init(cls.__init__)) return cls.objs[cls]['obj'] finally: cls.objs_locker.release() @classmethod def decorate_init(cls, fn): def init_wrap(*args): if not cls.objs[cls]['init']: fn(*args) cls.objs[cls]['init'] = True return return init_wrap class NoEmptyValueDict(dict): @staticmethod def _process_args(mapping = (), **kwargs): if hasattr(mapping, 'items'): mapping = getattr(mapping, 'items')() return ((k, v) for k, v in chain(mapping, getattr(kwargs, 'items')()) if v) def __setitem__(self, i, y): if y: super(NoEmptyValueDict, self).__setitem__(i, y) def update(self, E = None, **F): super(NoEmptyValueDict, self).update(self._process_args(E, **F)) def setdefault(self, k, d=None): if k in self: return super(NoEmptyValueDict, self).setdefault(k, d) if not d: return None else: return super(NoEmptyValueDict, self).setdefault(k, d) class NoInstantiateMeta(type): def __call__(cls, *args, **kwargs): raise TypeError("BaseIterConstant class cannot be instantiated.") class BaseIterConstant(object): """ 代替IterConstant基类 """ __metaclass__ = NoInstantiateMeta @classmethod def choice(cls, call=None): """ call 表示需要对获取的值执行的方法 比如int、str、float、lambda x: x+1 """ if call and callable(call): return [call(getattr(cls, attr)) for attr in dir(cls) if not attr.startswith("_") and attr.isupper()] else: return [getattr(cls, attr) for attr in dir(cls) if not attr.startswith("_") and attr.isupper()]