委托!反继承!

代码

完成了一般的委托功能,一个委托上挂多个函数,可以设置函数列表为空时,是否抛出异常。返回值是函数列表中最后一个函数调用的返回,使用方法可参见test部分。

   1 class delegate:
   2     def __init__(self, *calls, **opts):
   3         for call in calls:
   4             if not callable(call):
   5                 raise RuntimeError, str(call) + ' not a callable object'
   6         self.calls = () + calls
   7         self.emptyExcept = opts.get('emptyExcept', False)
   8         self.proto = opts.get('proto')
   9     def __call__(self, *args, **kwargs):
  10         if self.emptyExcept and not self.calls:
  11             raise RuntimeError, 'No callable objects'
  12 
  13         try:
  14             result = None
  15             for call in self.calls:
  16                 result = call (*args, **kwargs)
  17             return result
  18         except TypeError:
  19             raise RuntimeError, 'Invalid callable type: ' + str(call)
  20 
  21     def __add__(self, call):
  22         if not callable(call):
  23             raise RuntimeError, str(call) + ' not a callable object'
  24         return delegate(*(self.calls + (call,)))
  25 
  26     def __iadd__(self, *calls):
  27         self.calls += calls
  28         return self
  29 
  30     def __sub__(self, call):
  31         return delegate (*[x for x in self.calls if x != call])
  32 
  33     def __isub__(self, call):
  34         self.calls = tuple([x for x in self.calls if x != call])
  35         return self
  36 
  37     def __str__(self):
  38         if self.proto:
  39             return '<delegate object, proto type: %s>' % repr(self.proto)
  40         return repr(self)
  41 
  42     def clear (self):
  43         self.calls = []
  44 
  45     def bind (self, call):
  46         self.__iadd__(call)
  47 
  48     def unbind (self, call):
  49         if call not in self.calls:
  50             raise RuntimeError, str(call) + ' not bind'
  51         self.calls = tuple ([x for x in self.calls if x != call])
  52 
  53 if __name__ == '__main__':
  54     def a(v1, v2, **kwargs):
  55         print '\ta:', v1, v2
  56     def b(*args, **kwargs):
  57         print '\tb:', args, kwargs
  58     def c(v1, v2, **kwargs):
  59         print '\tc:', v1, v2, 'hello=', kwargs.get('hello')
  60 
  61     class Test:
  62         def hello(self, v1, v2, **kwargs):
  63             print '\tTest.hello:', v1, v2
  64 
  65     class Test1:
  66         def __call__(self, v1, v2, **kwargs):
  67             print '\tTest1.__call__:', v1, v2
  68 
  69     print '======== test delegate.__init__ and delegate.__call__'
  70     print '\t==== a, b, c, Test.hello, Test1'
  71     f = delegate(a, b, c, Test().hello, Test1())
  72     f (3, 4, hello='world')
  73     print '======== test delegate.__add__'
  74     print '\t==== a, b, c, Test.hello, Test1, a'
  75     f1 = f + a
  76     f1 (5, 6)
  77     print '======== test delegate.__iadd__'
  78     print '\t==== a, b'
  79     f2 = delegate(a, b)
  80     f2 (3, 7)
  81     print '\t==== a, b, c'
  82     f2 += c
  83     f2 (9, 10)
  84     print '======== test delegate.__sub__'
  85     print '\t==== a, b, c'
  86     f3 = delegate (a, b, c)
  87     f3 (11,11)
  88     print '\t==== b, c'
  89     f3 = f3 - a
  90     f3 (13, 13)
  91     print '\t==== b'
  92     f3 = f3 - c
  93     f3 (15, 15)
  94     print '======== test delegate.__isub__'
  95     print '\t==== a, b, c'
  96     f4 = delegate(a, b, c)
  97     f4 (17, 17)
  98     print '\t==== b, c'
  99     f4 -= a
 100     f4 (19, 19)
 101     print '\t==== c'
 102     f4 -= b
 103     f4 (21, 21)
 104     print '======== test delegate.__call__ return value'
 105     f3 = delegate(lambda x, y: x*y)
 106     assert f3(10, 11) == 10*11
 107     f3 = delegate(lambda x, y: x*y, lambda x, y: x**y)
 108     assert f3(10, 11) == 10**11
 109     print '======== test delegate.__call__ with empty exception (empty)'
 110     f4 = delegate (emptyExcept=True)
 111     try:
 112         f4 (3, 5)
 113     except RuntimeError, ex:
 114         print 'Exception:', ex
 115     print '======== test delegate.__call__ with empty exception (not empty)'
 116     f4 += a
 117     f4 (3, 5)
 118     print '======== test delegate.bind'
 119     print '\t==== a'
 120     f = delegate (a)
 121     f (911, 119)
 122     print '\t==== a, b'
 123     f.bind (b)
 124     f (199, 991)
 125     print '======== test delegate.unbind'
 126     print '\t==== b'
 127     f.unbind (a)
 128     f (177, 771)
 129     print '\t==== (empty)'
 130     f.unbind (b)
 131     f (133, 331)
 132     print '======== test delegate.clear'
 133     print '\t==== a, b'
 134     f = delegate (a, b)
 135     f (137, 138)
 136     print '\t==== (empty)'
 137     f.clear ()
 138     f (139, 139)
 139     print '======== (finished)'

讨论

功用1--扩展接口设计

   1 class NetConnection:
   2     def onConnected (self):
   3         pass
   4     def onDisconnected (self):
   5         pass
   6     def onReceived (self, data):
   7         pass
   8     def connect (self, address):
   9         pass
  10     def disconnect (self):
  11         pass
  12     def send (self, data):
  13         pass
  14 
  15 class AutoReconnectConnection(NetConnection):
  16     def onConnected (self):
  17         pass
  18     def onDisconnected (self):
  19         pass
  20 
  21 class AutoReconnectCommander(AutoReconnectConnection):
  22     def onReceived (self, data):
  23         pass

NetConnection类完成基本的网络连接,AutoReconnectConnection类有断线后自动重连的功能,AutoReconnectCommander则是把接收到的数据包转为指令或消息格式,这是一个普通的继承结构,没什么问题,使用时只要生成AutoReconnectCommander对象调用相关方法即可,接收到的数据在AutoReconnectCommander类中处理。

不过还有其它选择,这里用刚刚完成的delegate来做,示例如下:

   1 class NetConnection:
   2     def __init__ (self):
   3         self.onConnected = delegate (proto='onConnected()')
   4         self.onDisconnected = delegate (proto='onDisconnected()')
   5         self.onReceived = delegate(proto='onReceived(data)')
   6     def connect (self, address):
   7         pass
   8     def disconnect (self):
   9         pass
  10     
  11 class Commander:
  12     def __init__(self):
  13         self.send = delegate (proto='send(data)')
  14     def onReceived (self, data):
  15         pass
  16 
  17 class AutoReconnectProcessor:
  18     def __init__ (self):
  19         self.connect = delegate (proto='connect(address)')
  20     def onConnected (self):
  21         pass
  22     def onDisconnected (self):
  23         pass

注:delegate (proto='onConnected()')括号中的proto='...'其实现在没有使用,只是为了方便随时查阅要挂载的函数的原型。 这个调用过程会麻烦一些:

   1 # create objects
   2 connection = NetConnection ()
   3 commander = Commander ()
   4 auto_reconnect_processor = AutoReconnectProcessor()
   5 
   6 # process delegate
   7 connection.onConnected += auto_reconnect_processor.onConnected
   8 connection.onDisconnected += auto_reconnect_processor.onDisconnected
   9 connection.onReceived += commander.onReceived
  10 command.send += connection.send
  11 auto_reconnect_processor.connect = connection.connect

这个要很多步骤才完成一个初始化。但它带来了很多好处:

  1. 对象之间的行为绑定修改起来非常容易,比如这里要让某个连接断线后不重连,只要把它们之间的关系去掉即可;
  2. 插入行为非常容易,比如需要在接收到数据以后,把收到的数据复制一份到某文件,只要实现一个对象,并且具有与onReceived接口相容的调用形式同,并添加委托关系即可;要把发送的数据打印在屏幕,只需要实现一个与send相容的函数,在里面执行输出到屏幕,再添加委托关系即可;
  3. 每个部分的测试应该会比继承关系更容易,现在只需要为委托接口添加测试、输出或其它方式的测试代码即可。

总述

PythonDelegate (last edited 2009-12-25 07:09:16 by localhost)