2017-07-06 128 views
1

我想要做的是圍繞另一個模塊編寫一個包裝,以便可以將傳遞給其他模塊的方法的參數轉換爲其他模塊。這是相當混亂,所以這裏有一個例子:Python:你如何攔截一個方法調用來改變函數參數?

import somemodule 

class Wrapper: 
    def __init__(self): 
     self.transforms = {} 
     self.transforms["t"] = "test" 

    # This next function is the one I want to exist 
    # Please understand the lines below will not compile and are not real code 
    def __intercept__(self, item, *args, **kwargs): 
     if "t" in args: 
      args[args.index("t")] = self.transforms["t"] 
     return somemodule.item(*args, **kwargs) 

的目標是使包裝類的用戶對基礎模塊簡化呼叫,而無需重寫所有的功能模塊中。因此,在這種情況下,如果somemodule有一個函數調用print_uppercase那麼用戶可以做

w = Wrapper() 
w.print_uppercase("t") 

,並得到輸出

TEST 

我相信答案就在__getattr__,但我不完全知道如何將其用於此應用程序。

+0

@ D.Peter你能舉出一個這將如何應用的例子嗎?我相信你,我只是對嘲諷的文檔感到困惑。 –

回答

1

__getattr__結合上飛定義一個函數應該工作:

# somemodule 

def print_uppercase(x): 
    print(x.upper()) 

現在:

from functools import wraps 

import somemodule 

class Wrapper: 
    def __init__(self): 
     self.transforms = {} 
     self.transforms["t"] = "test" 

    def __getattr__(self, attr): 
     func = getattr(somemodule, attr) 
     @wraps(func) 
     def _wrapped(*args, **kwargs): 
      if "t" in args: 
       args = list(args) 
       args[args.index("t")] = self.transforms["t"] 
      return func(*args, **kwargs) 
     return _wrapped 


w = Wrapper() 
w.print_uppercase('Hello') 
w.print_uppercase('t') 

輸出:

HELLO 
TEST 
+0

'* args'不關心'args'是什麼樣的序列,所以不需要先創建一個元組。 – chepner

+0

@chepner謝謝。固定。 –

+0

@MikeMüller這就是我正要破解的東西。謝謝。 –

0

我會通過調用攔截方法,並輸入所需的方法來執行,作爲攔截參數。然後,在攔截方法中,您可以搜索具有該名稱的方法並執行它。

+0

這是可行的,但相當醜陋。它也打破了人們習慣使用底層模塊的方式。 –

0

由於您的Wrapper對象沒有任何可變狀態,所以在沒有類的情況下實現會更容易。例如wrapper.py

def func1(*args, **kwargs): 
    # do your transformations 
    return somemodule.func1(*args, **kwargs) 

然後調用它像:

import wrapper as w 
print w.func1('somearg')