Python: functools, оболочка-декоратор для методов: заставить ipython возвращать правильное определение при использовании '?'

Я использую functools для создания декоратора, который позволяет мне записывать детали вызова метода.

Мне здесь очень помогли написать это... это не мое, и я все еще учусь тому, как это вообще работает...

Я много работаю из ipython, и когда я использую:

import Tools
imagetools = Tools.Tools()
imagetools.save_new_image ?

Type:       instancemethod
String Form:<bound method ImageTools.save_new_image of <ImageTools.ImageTools object      at    0x305d1d0>>
File:       /fs/corpus6/dpc/workspace/python/Modules/MiscTools.py
Definition: imagetools.save_new_image(self, *args, **kwargs)
Docstring:  <no docstring>

Это моя проблема... кроме того, что я еще не написал строку документации...: |

Definition: imagetools.save_new_image(self, *args, **kwargs)

Я бы так и сделал:

save_new_image_clone(self, data, header, outfile,  coordmap)

Упаковочный:

import functools

def log_method(func):

@functools.wraps(func)
def wrapper(self, *args, **kwargs):
    self.__doc__ = func.__doc__
    # allows me to put the wrapper in helper methods that are sometimes major steps
    if check_for_True_in_last_arg(*args):
        log.debug('''Last arg is "True" which could indicate the caller 
intends the log to work on this method. For that behaviour, use the keyword arg:  log_this=True''')

    if 'log_this' in kwargs and kwargs['log_this'] is not False: 
        args_name = inspect.getargspec(func)[0][1:] #drop the 'self' arg
        args_dict = dict(list(itertools_izip(args_name, args)) + list(kwargs.iteritems()))
        method_name = wrapper.__name__
        args_dict_string = '\nMETHOD: ' + method_name + '\n'

        for k,v in args_dict.iteritems():
            if type(v) is not np.ndarray:
                args_dict_string += "%s: %s\n" %(k,v)

            elif type(v) is np.ndarray:
                args_dict_string += "NUMPY ARRAY:%s \nSHAPE:%s\n" %(k, str(v.shape))

        args_dict_string += '\n'
        log.info(args_dict_string)

    return func(self, *args, **kwargs) 

return wrapper

ОБНОВЛЕНИЕ: из ipython я сделал это, чтобы увидеть, что происходит, но это мне пока не помогло..

help??
Type:       _Helper
String Form:Type help() for interactive help, or help(object) for help about object.
File:       /usr/lib64/python2.7/site.py
Definition: help(self, *args, **kwds)
Source:

class _Helper(object):
"""Define the builtin 'help'.
This is a wrapper around pydoc.help (with a twist).

"""

def __repr__(self):
    return "Type help() for interactive help, " \
           "or help(object) for help about object."
def __call__(self, *args, **kwds):
    import pydoc
    return pydoc.help(*args, **kwds)

Call def:   help(self, *args, **kwds)

1 ответ

Решение

То, что вы пытаетесь сделать - создать декоратор, чья подпись вызова идентична декорируемой функции, - это не простая вещь с нуля. Существует сторонний модуль, называемый decorator, который может сделать это, однако:

import decorator

@decorator.decorator
def log_method(func, *args, **kwargs):
    # allows me to put the wrapper in helper methods that are sometimes major steps
    if check_for_True_in_last_arg(*args):
        log.debug('''Last arg is "True" which could indicate the caller 
intends the log to work on this method. For that behaviour, use the keyword arg:  log_this=True''')

    if 'log_this' in kwargs and kwargs['log_this'] is not False: 
        args_name = inspect.getargspec(func)[0][1:] #drop the 'self' arg
        args_dict = dict(list(itertools_izip(args_name, args)) + list(kwargs.iteritems()))
        method_name = wrapper.__name__
        args_dict_string = '\nMETHOD: ' + method_name + '\n'

        for k,v in args_dict.iteritems():
            if type(v) is not np.ndarray:
                args_dict_string += "%s: %s\n" %(k,v)

            elif type(v) is np.ndarray:
                args_dict_string += "NUMPY ARRAY:%s \nSHAPE:%s\n" %(k, str(v.shape))

        args_dict_string += '\n'
        log.info(args_dict_string)

    return func(self, *args, **kwargs) 

class Tools(object):
    @log_method
    def save_new_image(self, data, header, outfile, coordmap):
        """
        Jazz the snaz output baz
        """

Тогда из IPython:

In [14]: imagetools = Tools()

In [15]: imagetools.save_new_image?
Type:       instancemethod
String Form:<bound method Tools.save_new_image of <__main__.Tools object at 0xae1e20c>>
File:       /tmp/python-2973tNk.py
Definition: imagetools.save_new_image(self, data, header, outfile, coordmap)
Docstring:  Jazz the snaz output baz

Если вы хотите увидеть код Python, который достигает этого, обратитесь к классу decorator.FunctionMaker. Оно использует inspect чтобы выяснить сигнатуру исходной функции, а затем использует форматирование строки, чтобы написать def-statement определяя декорированную функцию. Тогда это вызывает exec code in evaldict выполнить строку.

Другие вопросы по тегам