2017-03-06 58 views
0

所以下面是一個非工作的例子,說明了什麼,我試圖讓在Python的裝飾與實例級別的信息

class TestClass(object): 

    def require_debug_mode(self, f): 
     def func_wrapper(*args, **kwargs): 
      if self.debug_mode: 
       return f(*args, **kwargs) 
     return func_wrapper 

    def __init__(self, debug_mode): 
     self.debug_mode = debug_mode 

    @require_debug_mode 
    def print_message(self, msg): 
     print msg 

你可以重新寫入所需的print_message如下所示:

def print_message(self, msg): 
    if self.debug_mode: 
     print msg 

我基本上希望能夠裝飾將執行某些檢查的方法(不必在可能使用它的每種方法中重複檢查)。但是這些檢查需要訪問實例級別的信息。這甚至有可能嗎?

+0

是的,它很容易成爲可能。你只是把'self'參數放在錯誤的地方。它是需要'self'參數的_inner_函數。 –

回答

1

要讓裝飾作爲類的一部分,你可以使用此代碼:

class TestClass(object): 

    def require_debug_mode(f): 
     def func_wrapper(self, *args, **kwargs): 
      if self.debug_mode: 
       return f(self, *args) 
     return func_wrapper 

    def __init__(self, debug_mode): 
     self.debug_mode = debug_mode 

    @require_debug_mode 
    def print_message(self, msg): 
     print(msg) 

tc_obj = TestClass(True) 
tc_obj.print_message("debug msg") 
# debug msg 

tc_obj = TestClass(False) 
tc_obj.print_message("debug msg") 
# no output 

爲了使裝飾類以外,你可以用下面的辦法

def require_debug_mode(f): 
    def wrapper(*args): 
     if args[0].debug_mode: 
      return f(*args) 
    return wrapper 

class TestClass(object): 
    def __init__(self, debug_mode): 
     self.debug_mode = debug_mode 

    @require_debug_mode 
    def print_message(self, msg): 
     print(msg) 

tc_obj = TestClass(True) 
tc_obj.print_message("debug msg") 
# debug msg 

tc_obj = TestClass(False) 
tc_obj.print_message("debug msg") 
# no output 
0

裝飾者收到與常規方法相同的參數,這意味着self也可用於裝飾者。你的代碼的問題在於你期望外部包裝獲得self參數,而不是這種情況(它在聲明時被調用,此時沒有實例)。

例如:

import functools 


class TestClass(object): 

    def require_debug_mode(function): 

     @functools.wraps(function) 
     def _require_debug_mode(self, *args, **kwargs): 
      assert self.debug_mode, 'Debug mode is required for %r' % function 
      return function(self, *args, **kwargs) 

     return _require_debug_mode 

    def __init__(self, debug_mode): 
     self.debug_mode = debug_mode 

    @require_debug_mode 
    def print_message(self, msg): 
     print msg 


test_class = TestClass(True) 
test_class.print_message('ping') 

test_class = TestClass(False) 
test_class.print_message('pong') 

輸出:

ping 
Traceback (most recent call last): 
    ... 
AssertionError: Debug mode is required for <function print_message at 0x...> 
shell returned 1 
0

裝飾器是一個函數,給定的函數作爲輸入,返回一個函數作爲輸出。

您想給作爲輸入功能print_message(self, msg)。沒關係。

爲了使裝飾器有效地工作,結果函數必須具有相似的行爲。所以,你想換的功能,解碼剛好足夠的參數,使「偷看」,看你想要什麼:

def func_wrapper(self, *args, **kwargs): 
    if self.debug_mode: 
     return self.f(*args, **kwargs)