2012-12-08 75 views
2

我有以下代碼,其中大部分代碼看起來很尷尬,令人困惑和/或根本性,但大部分代碼是演示更大代碼的哪些部分,有問題。請仔細閱讀如何使用__getattr__訪問調用參數和參數

# The following part is just to demonstrate the behavior AND CANNOT BE CHANGED UNDER NO CIRCUMSTANCES 
# Just define something so you can access something like derived.obj.foo(x) 
class Basic(object): 
    def foo(self, x=10): 
     return x*x 

class Derived(object): 
    def info(self, x): 
     return "Info of Derived: "+str(x) 
    def set(self, obj): 
     self.obj = obj 

# The following piece of code might be changed, but I would rather not 
class DeviceProxy(object): 
    def __init__(self): 
     # just to set up something that somewhat behaves as the real code in question 
     self.proxy = Derived() 
     self.proxy.set(Basic()) 

    # crucial part: I want any attributes forwarded to the proxy object here, without knowing beforehand what the names will be 
    def __getattr__(self, attr): 
     return getattr(self.proxy, attr) 

# ====================================== 
# This code is the only I want to change to get things work 

# Original __getattr__ function 
original = DeviceProxy.__getattr__ 

# wrapper for the __getattr__ function to log/print out any attribute/parameter/argument/... 
def mygetattr(device, key): 
    attr = original(device, key) 
    if callable(attr): 
     def wrapper(*args, **kw): 
      print('%r called with %r and %r' % (attr, args, kw)) 
      return attr(*args, **kw) 
     return wrapper 
    else: 
     print "not callable: ", attr 
     return attr 

DeviceProxy.__getattr__ = mygetattr 


# make an instance of the DeviceProxy class and call the double-dotted function 
dev = DeviceProxy() 
print dev.info(1) 
print dev.obj.foo(3) 

我要的是趕上所有的方法調用DeviceProxy到能夠打印所有的參數/參數等等。在給定的例子中,當調用info(1)時,這很好用,所有的信息都被打印出來。 但是,當我呼叫雙點功能dev.obj.foo(3),我只收到消息,這不是一個可調用的。

如何修改上述代碼,以便在第二種情況下獲得我的信息?只有===以下的代碼可以修改。

+0

問題是,對於'dev.obj.foo(3)','mygetattr'被設備'dev'和關鍵字'obj'調用,這實際上是不可調用的。你需要的是找出用設備'obj'和鍵'foo'調用它的方法。 (如何做到這一點對我來說並不明顯。) – khagler

+0

是的,這正是問題所在。看起來我需要另一層包裝或類似的東西,但我不確定有多少包裝。可能會有諸如'device.service.info.version.firmware'之類的調用。 – Alex

+0

據我所知,「基本」和「派生」不使用繼承,儘管名稱。 –

回答

3

你剛纔在dev一個__getattr__,你想,從這個__getattr__中,當你做dev.obj.foo有機會獲得foo。這是不可能的。屬性訪問不是一個整體訪問的「虛線函數」。屬性訪問的順序(點)從左到右逐個進行評估。當您訪問dev.obj時,無法知道您將稍後訪問foo。方法dev.__getattr__只知道您正在訪問哪些屬性dev,而不是您可能以後訪問該結果的屬性。

實現你想要的東西的唯一方法是在obj中也包含一些包裝行爲。你說你不能修改「Base」/「Derived」類,所以你不能這樣做。理論上,您可以不返回被訪問屬性的實際值,而是將該對象包裝在另一個代理中並返回代理。然而,這可能會有點棘手,並使你的代碼更難理解和調試,因爲你可以結束大量的對象被包裝在瘦代理中。