Python recipe(18):Monitor模式

代码:

div css xhtml xml Example Source Code 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)。即:根据自己的预期去执行任务,在此过程中检测并处理由于不匹配产生的所有错误和异常。

posted on 2010-05-30 00:19  tomsheep  阅读(1107)  评论(0编辑  收藏  举报

导航