2017-03-29 30 views
0

裝飾函數的最佳方式是什麼,但只能在本地範圍內。例如,我們有以下幾點:Python:只在本地裝飾函數的最佳方法

def a(): 
    do stuff 
    b() 
    do stuff 

我想打一個功能c(),做同樣的stuff但裝飾B上它增加了一些額外的東西。我發現了一個辦法做到這一點,但它改變B()全球:

def c(): 
    global b 
    b = decorator(b) 
    a() 

有沒有辦法做到這一點,但沒有改變全局函數B?

+0

'b = decorator(b)' - 我認爲這覆蓋了你的全局函數'b'。也許把它分配給另一個變量就是你要找的東西:'x = decorator(b)'。 – ikkuh

+0

不能是x,因爲我想在c()內部有不同的b函數,所以當我在c()內調用()時,a()是不同的,但只有當我在c()中調用它時() – edgarstack

回答

1

Python允許任何對象成爲可調用對象,而不僅僅是函數。

您可以使用類似:

class A(object): 
    def __init__(self, func=b): 
     self.func = func 
    def __call__(self): 
     # do stuff 
     self.func() 
     # do other stuff 

然後用a = A()a()會簡單地調用f,但如果你寫c = A(decorator(b))c()會因爲你重新綁定b()使調用裝飾版本

1

撥打a()將尊重更新的b(),您可以保存原始的b(),然後恢復。這可能不是最有效的方式,但它對我有用。

import copy 
def c(): 
    global b 
    orig_b = copy.deepcopy(b) 
    b = decorator(b) 
    a() 
    b = orig_b 
2

您可以修補函數b,並用另一個函數替換它。使用在Python 3 unittest.mock,或mock在Python 2本:

from unittest.mock import patch 

def c(): 
    with patch('b', decorator(b)): 
     a() 

# Or, as a decorator 
@patch('b', decorator(b)) 
def c(): 
    a() 

通過修補,你基本上用自己取代b實例。

+0

它可以工作,但你必須安裝模擬。而且它似乎有一個模擬問題,當它試圖安裝六個(這個問題似乎很常見) – edgarstack

+0

是的,雖然'mock'是Python 3標準庫的一部分。我不知道安裝'六'和'mock'雖然在Py 2.7中。 –