2017-02-26 2 views
1

これらの最初の2行だけを見てください。さまざまなパラメータを持つ関数にデコレータを使用するにはどうすればよいですか?

これらは関数です(パラメータと最初の2行を見るだけで、関数の内容はこの質問とは関係ありません)。

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 

どのように私はこれらのコードcheck_is_file()create_file_or_folder()のための装飾に

if not check_abs(_abs_dir): 
    return False 

を作ることができますか?両方の機能には異なるパラメータと位置があります。

答えて

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

Funnily十分に、私は、http、時々、同様の質問を:// howover-flow-questions/42510272/how-can-i-get-the-same-to-pass-parameters- between-decorator-and-decorated-functi。とにかくありがとうございました :)。 – notalentgeek

関連する問題