2017-02-26 31 views
1

只看這些的前兩行。如何使用裝飾器來處理具有各種參數的功能?

if not check_abs(_abs_dir): 
    return False 

這些是函數(只要看看參數和前兩行,函數的內容與這個問題無關)。

def check_is_file(_abs_dir:str): 
    if not check_abs(_abs_dir): 
     return False 

    return os.path.isfile(
     norm_case_norm_path(_abs_dir) 
    ) 

def create_file_or_folder(_name:str, _abs_dir:str, _is_file:bool): 
    if not check_abs(_abs_dir): 
     return False 

    abs_dir = join(_abs_dir, _name) 
    create = False 

    if check_existence(abs_dir): 
     if _is_file and not check_is_file(_abs_dir): 
      create = True 
     if not _is_file and not check_is_folder(_abs_dir): 
      create = True 
    else: 
     create = True 

    if create: 
     if _is_file: 
      open(abs_dir, "a").close() 
     elif not _is_file: 
      os.makedirs(abs_dir) 
     return create 

    return create 

我怎樣才能讓這些代碼

if not check_abs(_abs_dir): 
    return False 

進入裝飾爲check_is_file()create_file_or_folder()?兩種功能都有不同的參數和位置。

回答

0

問題是你不知道要檢查哪個參數,因爲它在你想裝飾的每個函數的不同位置。但是,您可以通過使用inspect模塊檢查每個函數的簽名來執行您想要的操作,請檢查並確保它具有帶指定名稱的參數,如果是,則將形式參數名稱映射到傳遞給該函數的實際參數值每次調用它。

有了這樣的信息使得有可能確定與目標參數相關聯的參數的值並處理它根據需要,這在您的代碼和在下面的例子是調用check_abs()功能與_abs_dir參數的值通過並檢查函數的返回值。

(注:修改,可支持多個命名參數)

from functools import wraps 
import inspect 

def check_abs(_abs_dir): 
    print('check_abs({!r}) called'.format(_abs_dir)) 
    return True 

def check_abs_param(*params): 
    def decorator(function): 
     sig = inspect.signature(function) 
     if any(map(lambda param: param not in sig.parameters, params)): 
      raise NameError('One or more expected parameter names missing from ' 
          'declaration "{}{}:".'.format(function.__name__, sig)) 
     @wraps(function) 
     def wrapped(*args, **kwargs): 
      bound = sig.bind(*args, **kwargs) # Map parameter names to argument values. 
      for param in params: 
       arg_value = bound.arguments[param] # Get argument value. 
       if not check_abs(arg_value): 
        return False if sig.return_annotation == bool else None 

      return function(*args, **kwargs) 
     return wrapped 
    return decorator 

# tests 
try: 
    @check_abs_param('_abs_dir') 
    def check_is_bogus(somearg): # param name does not match decorator 
     print('check_is_bogus() called\n') 
except NameError as exc: 
    print(exc) 
    print('NameError exception raised from "check_is_bogus(somearg):" declaration, as ' 
      'expected.\n') 
else: 
    print('Error: Expected exception NOT raised from "check_is_bogus(somearg):" ' 
      'declaration.\n') 

@check_abs_param('_abs_dir') 
def check_is_file(_abs_dir:str): 
    print('check_is_file() called\n') 

@check_abs_param('_abs_dir') 
def create_file_or_folder(_name:str, _abs_dir:str, _is_file:bool): 
    print('create_file_or_folder() called\n') 

@check_abs_param('source_dir_abs', 'dest_dir_abs') 
def copy_file_or_folder(source_dir_abs:str, dest_dir_abs:str) -> bool: 
    print('copy_file_or_folder() called\n') 

#check_is_bogus('first_dir') # can't call, definition failed 
check_is_file('second_dir') 
create_file_or_folder('name', 'third_dir', 'False') 
copy_file_or_folder('source_dir', 'dest_dir') 

輸出:

One or more expected parameter names missing from declaration "check_is_bogus(somearg):". 
NameError exception raised from "check_is_bogus(somearg):" declaration, as expected. 

check_abs('second_dir') called 
check_is_file() called 

check_abs('third_dir') called 
create_file_or_folder() called 

check_abs('source_dir') called 
check_abs('dest_dir') called 
copy_file_or_folder() called 
+0

有趣的是,我問過類似的問題,有時我在這裏張貼了這個問題,以後的http:// stackoverflow.com/questions/42510272/how-can-i-get-the-same-to-pass-parameters-between-decorator-and-decorated-functi。不管怎樣,謝謝你 :)。 – notalentgeek