# coding: utf-8 """封装常用的设计模式以及对内置函数和方法进行约定性的简化 """ import types import inspect from functools import wraps from girlfriend.exception import GirlFriendSysException _singletons = {} def singleton(clazz): """单例修饰器,被修饰的类在系统中都是单例的 非线程安全,请勿用在多线程环境当中 """ @wraps(clazz) def constructor(*args, **kws): global _singletons instance = _singletons.get(clazz) if instance is None: instance = clazz(*args, **kws) _singletons[clazz] = instance return instance return constructor class DelegateMeta(type): """该元类用于实现委托 基本用法: class A(object): __metaclass__ = DelegateMeta def __init__(self, delegate): self.delegate = delegate lst = [1,2,3] a = A(lst) a.append(4) 对象a的append方法会自动委托到lst对象的append方法。 这样可以满足多数情况,但是碰到内置方法比如__getitem__无法自动实现委托 如果要委托内置方法,那么需要通过类属性delegate_internal_methods去指明 class B(object): __metaclass__ = DelegateMeta delegate_internal_methods = ( "__getitem__", "__hash__", "__eq__" ) def __init__(self, delegate): self.delegate = delegate 需要值得注意的是,不要委托特殊方法:__init__、__new__ 另外还有__getattr__以及__getattribute__也不可以委托,因为DelegateMeta会用到这两个方法 如果需要在委托类中对访问属性做控制,那么可以使用__myattr__(self, fieldname) 对于未定义属性,DelegateMeta会优先拦截__myattr__,__myattr__通过抛出UnknownAttrError通知 委托类进行接下来的处理。 还可以使用delegate_methods属性显式指定委托方法: class C(object): __metaclass__ = DelegateMeta delegate_methods = ( "append", "__getitem__", "__eq__" ) def __init__(self, delegate): self.delegate = delegate """ class UnknownAttrError(GirlFriendSysException): pass def __new__(cls, name, bases, attrs): delegate_methods = attrs.get("delegate_methods", tuple()) if delegate_methods: DelegateMeta.register_delegates(delegate_methods, attrs) return type(name, bases, attrs) def getter(self, method_name): if "__myattr__" in attrs: try: return self.__myattr__(method_name) except DelegateMeta.UnknownAttrError: pass def method(*args, **kws): mtd = getattr(self.delegate, method_name) if mtd: return mtd(*args, **kws) else: raise AttributeError( "No method found %s" % method_name) return method attrs["__getattr__"] = getter # 痛! delegate_internal_methods = attrs.get( "delegate_internal_methods", tuple()) DelegateMeta.register_delegates(delegate_internal_methods, attrs) return type(name, bases, attrs) @staticmethod def register_delegates(delegate_methods, attrs): for mtd_name in delegate_methods: def make_method(method_name): def method(self, *args, **kws): return getattr(self.delegate, method_name)(*args, **kws) return method attrs[mtd_name] = make_method(mtd_name) def args2fields(private=True): """专门是应用于构造函数的修饰器 可以将构造函数除self以外的参数悉数赋值给类属性 比如 class A(object): def __init__(self, a, b, c): self._a = a self._b = b self._c = c self.sum = self._a + self._b + self._c 只要写成这样就好: class A(object): @args2fields() def __init__(self, a, b, c): self.sum = self._a + self._b + self._c 不必再去写上面那些无聊的赋值语句了 :param private 是否转变为私有字段,如果为True,那么会在所有字段名前加个下划线 """ def _field_name(arg_name): return "_" + arg_name if private else arg_name def _args2fields(constructor): @wraps(constructor) def _wrapped_constuctor(self, *args, **kws): args_spec = inspect.getargspec(constructor) for idx, arg in enumerate(args, start=1): arg_name = args_spec.args[idx] field_name = _field_name(arg_name) setattr(self, field_name, arg) for arg_name, arg in kws.items(): field_name = _field_name(arg_name) setattr(self, field_name, arg) # 处理没有赋值的默认参数 default_args = get_default_args(args_spec) if default_args: for arg_name, default_value in default_args.items(): if arg_name == "self": continue field_name = _field_name(arg_name) if hasattr(self, field_name): continue setattr(self, field_name, default_value) constructor(self, *args, **kws) return _wrapped_constuctor return _args2fields def get_default_args(o): """获取函数的默认参数名-值映射 """ argspec = o if not isinstance(o, inspect.ArgSpec): argspec = inspect.getargspec(o) if not argspec.defaults: return {} return dict(zip(argspec.args[-len(argspec.defaults):], argspec.defaults)) # 线性集合类型 SequenceCollectionType = (types.ListType, types.TupleType) def parse_context_var(context, variable_name): """解析上下文中的变量 如果以'$'字符开头,那么返回上下文中的对应变量 其它的情况会直接返回字符串 开头两个$$连续为转义,比如'$$aa$$a'为'$aa$$a' :param context 上下文 :param variable_name """ if not isinstance(variable_name, str): return variable_name elif variable_name.startswith("$$"): return variable_name.replace("$$", "$") elif variable_name.startswith("$"): return context[variable_name[1:]] else: return variable_name class ObjDictModel(object): def __getattr__(self, name): return self.__dict__[name] def __setattr__(self, name, value): self.__dict__[name] = value def __getitem__(self, name): return self.__dict__[name] def __setitem__(self, name, value): self.__dict__[name] = value class SafeOperation(object): """包装一个对象进行安全操作, 像某些语言的安全操作符 避免None引用引发的错误 每年空指针错误带来的损失是十个亿啊,还是美元!同志们! """ def __init__(self, obj): self.__dict__["_SafeOperation__obj"] = obj def __getattr__(self, attrname): obj = self.__dict__["_SafeOperation__obj"] if obj is None: return self return getattr(obj, attrname) def __setattr__(self, attrname, value): obj = self.__obj if obj is None: return return setattr(obj, attrname, value) def __call__(self, *args, **kwds): return self