Python recipe(18):Monitor模式
代码:
Example Source Code [http://www.cnblogs.com/tomsheep/]
''' Created on 2010-5-29 @author: lk ''' import types def _get_method_names(obj): """ Get all methods of a class or instance, inherited or otherwise. """ if type(obj) == types.InstanceType: return _get_method_names(obj.__class__) elif type(obj) == types.ClassType or type(obj) == types.TypeType: result = [] for name, func in obj.__dict__.items( ): if type(func) == types.FunctionType: result.append((name, func)) for base in obj.__bases__: result.extend(_get_method_names(base)) return result class _SynchronizedMethod: def __init__(self, method, obj, lock): self.__method = method self.__obj = obj self.__lock = lock def __call__(self, *args, **kwargs): self.__lock.acquire( ) try: return self.__method(self.__obj, *args, **kwargs) finally: self.__lock.release( ) class SynchronizedObject: def __init__(self, obj, ignore=[], lock=None): import threading # You must access __dict__ directly to avoid tickling __setattr__ self.__dict__['_SynchronizedObject__methods'] = {} self.__dict__['_SynchronizedObject__obj'] = obj if not lock: lock = threading.RLock( ) for name, method in _get_method_names(obj): if not name in ignore and not self.__methods.has_key(name): self.__methods[name] = _SynchronizedMethod(method, obj, lock) def __getattr__(self, name): #EAFP: Easier to ask for forgiveness than permission try: return self.__methods[name] except KeyError: return getattr(self.__obj, name) def __setattr__(self, name, value): setattr(self.__obj, name, value) class A(object): @staticmethod def f0():pass def f1(self):pass def f2(self):pass class B(): def f1(self):pass if __name__ == '__main__': print _get_method_names(A) print _get_method_names(B) import threading import time class Dummy: def foo (self): print 'hello from foo' time.sleep(1) def bar (self): print 'hello from bar' def baaz (self): print 'hello from baaz' tw = SynchronizedObject(Dummy( ), ignore=['baaz']) threading.Thread(target=tw.foo).start( ) time.sleep(.1) threading.Thread(target=tw.bar).start( ) time.sleep(.1) threading.Thread(target=tw.baaz).start( )
以上代码改写自Python Cookbook 6-6
概述:
模拟Java中的Monitor模式,即所有方法都synchronized。Java中利用intrinsic锁来实现,这里我们用Wrapper把一个Lock和一个object绑定。
代码说明:
1. get_method_names函数获取一个对象对应的所有函数,这里将书中代码稍作修改以支持新式class(type(obj) == types.ClassType or type(obj) == types.TypeType)
2.注意到self.__dict__['_SynchronizedObject__methods'] 这样Key的命名,这是因为在类的instance对象的字典(__dict__)中, 其域的命名会变为_ClassName__FiledName, 当该对象obj访问成员obj.__FileName时,其实就是从字典中去找_ClassName__FiledName这个键。这里为什么不直接self.__methods来访问呢?注释中已经说明,为了防止调用__setattr__
3.__getattr__函数的编写方式是Python中常用的EAFP模式(Easier to Ask for Forgiveness than Permission)。即:根据自己的预期去执行任务,在此过程中检测并处理由于不匹配产生的所有错误和异常。