2011-06-01 8 views
12

मैं एक ऐसा फ़ंक्शन बनाना चाहता हूं जो किसी अन्य फ़ंक्शन में सजावट करने वाला फ़ंक्शन कॉल विवरण प्रिंट करेगा - पैरामीटर नाम और प्रभावी मान। मेरा वर्तमान कार्यान्वयन यह है।फ़ंक्शन कॉल विवरण मुद्रित करने के लिए सजावटी - पैरामीटर नाम और प्रभावी मान

def describeFuncCall(func): 
    '''Decorator to print function call details - parameters names and effective values''' 
    def wrapper(*func_args, **func_kwargs): 
     print 'func_code.co_varnames =', func.func_code.co_varnames 
     print 'func_code.co_argcount =', func.func_code.co_argcount 
     print 'func_args =', func_args 
     print 'func_kwargs =', func_kwargs 
     params = [] 
     for argNo in range(func.func_code.co_argcount): 
      argName = func.func_code.co_varnames[argNo] 
      argValue = func_args[argNo] if argNo < len(func_args) else func.func_defaults[argNo - func.func_code.co_argcount] 
      params.append((argName, argValue)) 
     for argName, argValue in func_kwargs.items(): 
      params.append((argName, argValue)) 
     params = [ argName + ' = ' + repr(argValue) for argName, argValue in params] 
     print(func.__name__ + ' (' + ', '.join(params) + ')') 
     return func(*func_args, **func_kwargs) 
    return wrapper 


@describeFuncCall 
def test(a, b = 4, c = 'blah-blah', *args, **kwargs): 
    pass 


test(1) 
#test(1, 3) 
#test(1, d = 5) 
test(1, 2, 3, 4, 5, d = 6, g = 12.9) 

किंडा काम करता है, लेकिन कुछ कीड़े के साथ:

कॉल

लिए

test(1, 2, 3, 4, 5, d = 6, g = 12.9)

यह प्रिंट

test (a = 1, b = 2, c = 3, d = 6, g = 12.9)

अपेक्षित परिणाम

test (a = 1, b = 2, c = 3, args = [4, 5], kwargs = {'d': 6, 'g': 12.9})

मैं यहाँ अटक गया है। क्या आप सही समाधान खोजने में मेरी मदद कर सकते हैं?

+0

यदि यह डिबगिंग के लिए है, तो यह फ़ंक्शन रिटर्न वैल्यू दिखाने के लिए भी उपयोगी नहीं हो सकता है? – Curt

+0

@Curt हाँ, यकीन है कि – warvariuc

उत्तर

11

क्षमा करें यह थोड़ा गन्दा है।

परीक्षण (एक = 1, बी: मैं http://wiki.python.org/moin/PythonDecoratorLibrary#Easy_Dump_of_Function_Arguments

def dump_args(func): 
    "This decorator dumps out the arguments passed to a function before calling it" 
    argnames = func.func_code.co_varnames[:func.func_code.co_argcount] 
    fname = func.func_name 
    def echo_func(*args,**kwargs): 
     print fname, "(", ', '.join(
      '%s=%r' % entry 
      for entry in zip(argnames,args[:len(argnames)])+[("args",list(args[len(argnames):]))]+[("kwargs",kwargs)]) +")" 
    return echo_func 

@dump_args 
def test(a, b = 4, c = 'blah-blah', *args, **kwargs): 
    pass 

परीक्षण (1, 2, 3, 4, 5, घ = 6, जी = 12.9)

उत्पादन से कुछ कोड को संशोधित किया = 2, सी = 3, आर्ग = [4, 5], kwargs = { 'प': 6, 'जी': 12.9} मूलभूत मूल्यों के साथ)

+0

यह कुछ कीड़े जो मैं तय है, लेकिन यह ध्यान मूलभूत मूल्यों पर ध्यान नहीं देता: 'परीक्षण (1)': परीक्षण (एक = 1, आर्ग =(), kwargs = {}) – warvariuc

6

कार्य संस्करण:

def dumpArgs(func): 
    '''Decorator to print function call details - parameters names and effective values''' 
    def wrapper(*func_args, **func_kwargs): 
     arg_names = func.func_code.co_varnames[:func.func_code.co_argcount] 
     args = func_args[:len(arg_names)] 
     defaults = func.func_defaults or() 
     args = args + defaults[len(defaults) - (func.func_code.co_argcount - len(args)):] 
     params = zip(arg_names, args) 
     args = func_args[len(arg_names):] 
     if args: params.append(('args', args)) 
     if func_kwargs: params.append(('kwargs', func_kwargs)) 
     print func.func_name + ' (' + ', '.join('%s = %r' % p for p in params) + ')' 
     return func(*func_args, **func_kwargs) 
    return wrapper 

@dumpArgs 
def test(a, b = 4, c = 'blah-blah', *args, **kwargs): 
    pass 

test(1) 
test(1, 3) 
test(1, d = 5) 
test(1, 2, 3, 4, 5, d = 6, g = 12.9) 

परिणाम:

>>> test ( a = 1, b = 4, c = 'blah-blah') 
test ( a = 1, b = 3, c = 'blah-blah') 
test ( a = 1, b = 4, c = 'blah-blah', kwargs = {'d': 5}) 
test ( a = 1, b = 2, c = 3, args = (4, 5), kwargs = {'d': 6, 'g': 12.9}) 
+2

यह प्रश्न पुराना है लेकिन अभी भी उपयोगी है। आपको ध्यान रखना चाहिए कि कोर लाइब्रेरी इस मैपिंग को '* args' और '** kwargs' से वास्तविक पैरामीटर नामों में करने के लिए एक मानक तरीका बताती है: [Signature.bind] (https://docs.python.org/3/library /inspect.html#inspect.Signature.bind) – Demurgos

4

@ warvariuc का जवाब, अजगर 3 करने के लिए उन्नत:

def dumpArgs(func): 
    '''Decorator to print function call details - parameters names and effective values''' 
    def wrapper(*func_args, **func_kwargs): 
     arg_names = func.__code__.co_varnames[:func.__code__.co_argcount] 
     args = func_args[:len(arg_names)] 
     defaults = func.__defaults__ or() 
     args = args + defaults[len(defaults) - (func.__code__.co_argcount - len(args)):] 
     params = list(zip(arg_names, args)) 
     args = func_args[len(arg_names):] 
     if args: params.append(('args', args)) 
     if func_kwargs: params.append(('kwargs', func_kwargs)) 
     print(func.__name__ + ' (' + ', '.join('%s = %r' % p for p in params) + ')') 
     return func(*func_args, **func_kwargs) 
    return wrapper 

@dumpArgs 
def test(a, b = 4, c = 'blah-blah', *args, **kwargs): 
    pass 

test(1) 
test(1, 3) 
test(1, d = 5) 
test(1, 2, 3, 4, 5, d = 6, g = 12.9) 
+0

'सूची (ज़िप (...))' भाग के लिए @Ffisegydd के लिए धन्यवाद के साथ। – aliteralmind

4

यहाँ कैसे मैं aliteralmind's उत्तर के आधार पर पायथन 3 में इसे हल, अधिक सफाई से (PEP8) डाल अगर मैं इतना कह सकते हैं। सफाई के लिए प्रेरणा का अधिकांश हिस्सा वर्तमान में accepted answerRobert King से आया था।

कोड:

import logging 


def log_function_entry_and_exit(decorated_function): 
    """ 
    Function decorator logging entry + exit and parameters of functions. 

    Entry and exit as logging.info, parameters as logging.DEBUG. 
    """ 
    from functools import wraps 

    @wraps(decorated_function) 
    def wrapper(*dec_fn_args, **dec_fn_kwargs): 
     # Log function entry 
     func_name = decorated_function.__name__ 
     log = logging.getLogger(func_name) 
     log.info('Entering {}()...'.format(func_name)) 

     # get function params (args and kwargs) 
     arg_names = decorated_function.__code__.co_varnames 
     params = dict(
      args=dict(zip(arg_names, dec_fn_args)), 
      kwargs=dec_fn_kwargs) 

     log.debug(
      "\t" + ', '.join([ 
       '{}={}'.format(str(k), repr(v)) for k, v in params.items()])) 
     # Execute wrapped (decorated) function: 
     out = decorated_function(*dec_fn_args, **dec_fn_kwargs) 
     log.info('Done running {}()!'.format(func_name)) 

     return out 
    return wrapper 


@log_function_entry_and_exit 
def func1(a, b, c): 
    print("\n\ty'elo2!\n") 
@log_function_entry_and_exit 
def a(x, y, z): 
    print("\n\ty'elo!\n") 

LOG_FORMAT = '[{}] !%(levelname)s! %(funcName)s: %(message)s'.format(
    _get_current_time_string(just_time_string=True)) 
logging.basicConfig(format=LOG_FORMAT, level=logging.DEBUG) 

a(x=1, y="b", z={'c': 2}) 
func1(2, b="y", c={'z': 4}) 
func1(2, "y", {'z': 4}) 

आउटपुट:

In [6]: a(x=1, y="b", z={'c': 2}) 
    ...: func1(2, b="y", c={'z': 4}) 
    ...: func1(2, "y", {'z': 4}) 
    ...: 
[2016.09.22 - 17:31:48] !INFO! wrapper: Entering a()... 
[2016.09.22 - 17:31:48] !DEBUG! wrapper:  kwargs={'x': 1, 'z': {'c': 2}, 'y': 'b'}, args={} 

     y'elo! 

[2016.09.22 - 17:31:48] !INFO! wrapper: Done running a()! 
[2016.09.22 - 17:31:48] !INFO! wrapper: Entering func1()... 
[2016.09.22 - 17:31:48] !DEBUG! wrapper:  kwargs={'c': {'z': 4}, 'b': 'y'}, args={'a': 2} 

     y'elo2! 

[2016.09.22 - 17:31:48] !INFO! wrapper: Done running func1()! 
[2016.09.22 - 17:31:48] !INFO! wrapper: Entering func1()... 
[2016.09.22 - 17:31:48] !DEBUG! wrapper:  kwargs={}, args={'c': {'z': 4}, 'a': 2, 'b': 'y'} 

     y'elo2! 

[2016.09.22 - 17:31:48] !INFO! wrapper: Done running func1()! 

नोट: उत्पादन में wrapper स्ट्रिंग जो कुछ logging.X() संदेश कॉल करता है के समारोह नाम का प्रतिनिधित्व करता है।प्रयोग में

उदाहरण:

In [1]: from meh import execute_os_command 

In [2]: from meh import LOG_FORMAT 

In [3]: import logging 

In [4]:  logging.basicConfig(format=LOG_FORMAT, level=logging.INFO) 
    ...: 
    ...:  logging.info("Entered script...\n") 
    ...: 
    ...:  result = execute_os_command(cmd=["echo", "trololol"]) 
    ...:  print("\n{}\n".format(result)) 
    ...:  execute_os_command(cmd=["echo", "trololol"], dry_run=True) 
    ...: 
    ...:  logging.info("Exiting script...\n") 
    ...: 
[2016.09.22 - 17:42:19] !INFO! <module>: Entered script... 

[2016.09.22 - 17:42:19] !INFO! wrapper: Entering execute_os_command()... 
[2016.09.22 - 17:42:19] !INFO! execute_os_command: Executing: 
[2016.09.22 - 17:42:19] !INFO! execute_os_command:  echo trololol 
[2016.09.22 - 17:42:19] !INFO! execute_os_command: Waiting for above command to finish execution... 
[2016.09.22 - 17:42:19] !INFO! wrapper: Done running execute_os_command()! 

{'stderr': '', 'stdout': 'trololol\n', 'command': ['echo', 'trololol'], 'returncode': 0, 'stdin': None, 'timedout': False} 

[2016.09.22 - 17:42:19] !INFO! wrapper: Entering execute_os_command()... 
[2016.09.22 - 17:42:19] !INFO! execute_os_command: Would have executed: 
[2016.09.22 - 17:42:19] !INFO! execute_os_command:  echo trololol 
[2016.09.22 - 17:42:19] !INFO! execute_os_command: Exiting execute_os_command()... 
[2016.09.22 - 17:42:19] !INFO! wrapper: Done running execute_os_command()! 
[2016.09.22 - 17:42:19] !INFO! <module>: Exiting script... 


In [5]: 

जब मैं जादुई "के रूप में समय और ऊर्जा" के नाम से संसाधनों मिलता है, मैं LOG_FORMAT के साथ चारों ओर खेलने में रूचि हूँ, और यह पता लगाने की कैसे मैं साथ wrapper-स्ट्रिंग की जगह ले सकता फ़ंक्शन आमंत्रण के फ़ाइल नाम और लिनेनंबर = =

संबंधित मुद्दे