2014-06-27 34 views
0

這應該可以解釋我想實現Python的遞歸代理

class A(object): 
    def hello(self): 
     print "hello" 

a = A() 
a.b = A() 
a.b.c = A() 
a.b.d = [] 
a.b.d.append(A()) 


p = Proxy(a) 

print p.b 
"b accessed" 
<__main__.A object at 0xb73f3bec> 

print p.b.c 
"b accessed" 
"c accessed" 
<__main__.A object at 0xb73f3dec> 

print p.b.d 
"b accessed" 
"d accessed" 
[<__main__.A object at 0xb73f3bcc>] 

print p.b.d[0] 
"b accessed" 
"d accessed" 
<__main__.A object at 0xb73e766c> 

print p.b.d[0].hello() 
"b accessed" 
"d accessed" 
"hello called" 
"hello" 

基本上只要我走它使返回的代理對象的結構。如果只在第一次訪問該屬性並將其存儲在「父」時​​才創建這些代理對象,那將是最好的。這樣做的目的是爲了讓我能做到這之前的任何方法稱爲(嵌套)對象

我有看一些邏輯: http://code.activestate.com/recipes/496741-object-proxying/ 但它只做了第一層,而我不能看看如何操作它來按需要工作。

回答

0

使用全局緩存,並創建一個代理工廠方法,該方法首先在創建新代理之前檢查全局緩存。

請注意,此解決方案不會在「父」上存儲子代理對象。相反,它使用id(obj)技巧來從緩存中檢索對象,無論其深度如何。

NOT_FOUND = object() 

# global proxy cache 
_id2obj_dict = {} 

def remember(oid, proxy): 
    _id2obj_dict[oid] = proxy 
    return oid 

def id2obj(oid): 
    print("accessing cahed object") 
    return _id2obj_dict[oid] 

class A(object): 
    def hello(self): 
     print "hello" 

class Proxy(object): 
    @classmethod 
    def create(cls, obj): 
     ''' object factory ''' 
     oid = id(obj) 
     if oid in _id2obj_dict: 
      return id2obj(oid) 
     proxy = cls() 
     proxy.obj = obj 
     remember(oid, proxy) 
     return proxy 
    def __getattr__(self, attr): 
     prop = getattr(self.obj, attr, NOT_FOUND) 
     if prop is NOT_FOUND: 
      raise AttributeError() 
     print("{} accessed".format(attr)) 
     proxy = Proxy.create(prop) 
     return proxy 
    def __getitem__(self, index): 
     prop = self.obj.__getitem__(index) 
     proxy = Proxy.create(prop) 
     return proxy 
    def __call__(self): 
     print("{} called".format(self.obj.__name__)) 
     return self.obj() 



a = A() 
a.b = A() 
a.b.c = A() 
a.b.d = [] 
a.b.d.append(A()) 


p = Proxy.create(a) 
0

有考慮與遞歸代理,不同的權衡幾個選擇:

  1. 覆蓋類

    也許是最好的和最容易實現的選擇。製作一個用代理類替換類的裝飾器。您可以使代理更加智能化,以便在實例上設置代理行爲標誌之前,類可以像正常一樣運行。

    例如:

    @ProxyWhenFlag('__turn_on_proxy__') 
    class A: 
        def hello(self): 
         print "hello" 
    
    a = A() 
    a.b = A() 
    a.b.c = A() 
    a.b.d = [] 
    a.b.d.append(A()) 
    

    用法:

    >>> a.b 
    <__main__.A object at 0xb73f3bec> 
    >>> a.__turn_on_proxy__ = True 
    >>> a.b 
    "b accessed" 
    <__main__.A object at 0xb73f3bec> 
    
  2. 通過重寫__getattribute__

    的簡單方法將修改實例

    可以攔截最屬性訪問的對象是做一個imprint您的代理的方法,它刪除所有其他方法,並且只允許通過代理方法訪問基礎對象。

    注意__基礎的方法將必須單獨覆蓋(它們沒有被截獲__getattribute__)。 Tuples,對象與__slots__和數據結構(ListDictSet等)所有被優化,並且__getattribute__將無法​​正常工作或者有

    一個更復雜的方法是標記對象作爲代理,並採取通過覆蓋代理Object,Tuple,List,Dict,Set等來檢查該標誌。您可以使用forbiddenfruit模塊來覆蓋內置方法。這樣做要特別小心。這非常重要,並且會影響整個應用程序的性能。它仍然可能是值得的,但如果你要代理幾乎所有的東西(程序分析/追蹤/ AOP框架等)。)

  3. 使用全局高速緩存

    可能是最符合成本效益的選擇,因爲MBarsi指出。但是,如果您想將代理注入其他代碼,您仍然需要使用代理對象獲取其他代碼。