2008-12-04 44 views
1

我想在IronPython中做一個代理對象,它應該動態地呈現底層結構。代理本身不應該有任何函數和屬性,我試圖捕獲運行時的所有調用。捕捉函數調用很容易,我只需要爲我的對象定義getattr()函數,並檢查底層中是否存在適當的函數,並返回一些類似函數的對象。IronPython中的代理對象

我有性能問題 - 我不知道如何區分調用上下文,是我的財產被稱爲一個左值或右值:

O = myproxy.myproperty#我需要調用underlying.myproperty_get ()

myproxy.myproperty = O#我需要調用underlying.myproperty_set(O)

我查看了Python中的特殊函數列表,但我沒有找到任何適合的東西。我還試圖通過exec()和builtin property()函數的組合來動態創建對象中的屬性,但是我發現IronPython 1.1.2缺少整個「新」模塊(它存在於IronPython 2.x測試版,但我寧願使用IP 1.x,因爲.NET 2.0框架)。

任何想法?

+0

夥計們,非常感謝你! – apetrovic 2010-12-24 08:24:09

回答

2

通常的實現你想要的蟒蛇什麼會是這樣的:

class CallProxy(object): 
    'this class wraps a callable in an object' 
    def __init__(self, fun): 
     self.fun = fun 

    def __call__(self, *args, **kwargs): 
     return self.fun(*args, **kwargs) 

class ObjProxy(object): 
    ''' a proxy object intercepting attribute access 
    ''' 
    def __init__(self, obj): 
     self.__dict__['_ObjProxy__obj'] = obj 

    def __getattr__(self, name): 
     attr = getattr(self.__obj, name) 
     if callable(attr): 
      return CallProxy(attr) 
     else: 
      return attr 

    def __setattr__(self, name, value): 
     setattr(self.__obj, name, value) 

我寫了一個測試,以證明這種行爲與預期:

#keep a list of calls to the TestObj for verification 
call_log = list() 
class TestObj(object): 
    ''' test object on which to prove 
     that the proxy implementation is correct 
    ''' 
    def __init__(self): 
     #example attribute 
     self.a = 1 
     self._c = 3 

    def b(self): 
     'example method' 
     call_log.append('b') 
     return 2 

    def get_c(self): 
     call_log.append('get_c') 
     return self._c 
    def set_c(self, value): 
     call_log.append('set_c') 
     self._c = value 
    c = property(get_c, set_c, 'example property') 

def verify(obj, a_val, b_val, c_val): 
    'testing of the usual object semantics' 
    assert obj.a == a_val 
    obj.a = a_val + 1 
    assert obj.a == a_val + 1 
    assert obj.b() == b_val 
    assert call_log[-1] == 'b' 
    assert obj.c == c_val 
    assert call_log[-1] == 'get_c' 
    obj.c = c_val + 1 
    assert call_log[-1] == 'set_c' 
    assert obj.c == c_val + 1 

def test(): 
    test = TestObj() 
    proxy = ObjProxy(test) 
    #check validity of the test 
    verify(test, 1, 2, 3) 
    #check proxy equivalent behavior 
    verify(proxy, 2, 2, 4) 
    #check that change is in the original object 
    verify(test, 3, 2, 5) 

if __name__ == '__main__': 
    test() 

這對CPython的執行沒有任何斷言拋出異常。 IronPython應該是等價的,否則它會被破壞,這個測試應該被添加到它的單元測試套件中。

2

試試這個:

class Test(object): 
    _test = 0 

    def test(): 
     def fget(self): 
      return self._test 
     def fset(self, value): 
      self._test = value 
     return locals() 
    test = property(**test()) 

    def greet(self, name): 
     print "hello", name 


class Proxy(object): 
    def __init__(self, obj): 
     self._obj = obj 

    def __getattribute__(self, key): 
     obj = object.__getattribute__(self, "_obj") 
     return getattr(obj, key) 

    def __setattr__(self, name, value): 
     if name == "_obj": 
      object.__setattr__(self, name, value) 
     else: 
      obj = object.__getattribute__(self, "_obj") 
      setattr(obj, name, value) 


t = Test() 
p = Proxy(t) 
p.test = 1 
assert t.test == p.test 
p.greet("world")