2009-10-30 4 views
24

Это первый пример, который мы встречаем, когда сталкиваемся с декораторами. Но я не могу понять, что именно хотел.Каротаж Python с использованием декоратора

Простой декоратор с именем LOG. Он должен работать так:

@LOG 
def f(a, b=2, *c, **d): 
    pass 

И результат должен быть что-то вроде:

f(1, pippo=4, paperino='luca') 
===== Enter f ===== 
a = 1 
b = 2 
pippo = 4 
paperino = luca 
===== Exit f ===== 

Где каждый аргумент, передаваемый в качестве параметра функции предъявляется с его значением.

Я обнаружил, что проблема сложнее, чем я думал, в основном из-за множества различных способов передачи аргументов функции (подумайте о кортежах с помощью * c или словарей с ** d).

Я пробовал решение, но я не уверен, что это правильно. Это somethink так:

def LOG(fn): 
    import inspect 
    varList, _, _, default = inspect.getargspec(fn) 
    d = {} 
    if default is not None: 
     d = dict((varList[-len(default):][i], v) for i, v in enumerate(default)) 
    def f(*argt, **argd): 
     print ('Enter %s' % fn).center(100, '=') 
     d.update(dict((varList[i], v) for i, v in enumerate(argt))) 
     d.update(argd) 
     for c in d.iteritems(): 
      print '%s = %s' % c 
     ret = fn(*argt, **argd) 
     print 'return: %s' % ret 
     print ('Exit %s' % fn).center(100, '=') 
     return ret 
    return f 

Я думаю, что это не так просто, как я ожидал, но это странно, что я не нашел то, что я хотел на Google.

Можете ли вы сказать мне, если мое решение в порядке? Или вы можете предложить лучшее решение проблемы, которую я предложил?

Спасибо всем.

+2

Это работает? Если это сработает, тогда все в порядке. Если это не так, у вас возникнет проблема. Задайте нам конкретный вопрос об этой проблеме. –

+0

Да, ты прав. На самом деле это работает. Но, как я уже писал, существует множество сложных способов передать аргументы функции Python: с использованием кортежей, словарей, аргументов по умолчанию, ... Фактически, даже если это работает, я не уверен, что это правильные реализации, они будут работать в каждом случае. – Luca

+2

Попадая в жертву самому себе, эта функция в абсолютно общей форме, которую вы описываете, необходима для продолжения разработки вашего приложения? Похоже, что сам механизм каротажа привлек ваше внимание, и я знаю по опыту, что может быть ужасным убийцей производительности. –

ответ

5

Единственное, что я заметил, это то, что созданная вами конструкция dict((varList[i], v) for i, v in enumerate(argt)) фактически используется на самом деле dict(zip(varList,argt)).

Кроме этого, у меня есть только метакритичность: ни один из перечисленных выше не принадлежит в файле журнала.

Вместо того, чтобы идти корыто журналов

  • увидеть, если функции вызываются с правильными аргументами, которые вы используете утверждает и отладчик.
  • Посмотрите, вернет ли функция правильные результаты, которые вы пишете unittests.
+0

Вы могли бы разработать/дать ссылки на (1), пожалуйста? –

+2

Благодарим вас за полезную функцию zip. Я думаю, вы правы для метакритики. Я разрабатываю на удаленной машине, и я не могу использовать отладчик. Таким образом, этот меганизм журналов должен быть способом отладки простым способом. – Luca

1

В вашей функции все в порядке. Кажется, вы потерялись с помощью позиционных переменных vs variable &.

Позвольте мне объяснить: позиционные аргументы, a и b в вашем случае являются обязательными (и могут иметь значения по умолчанию). Другие аргументы являются необязательными. Если вы хотите сделать аргумент обязательным или иметь значение по умолчанию, поставьте его перед * args и ** kwargs. Но помните, что вы не можете поставить аргумент дважды:

def x(a = 1, b = 2, *args, **kwargs): 
    print a, b, args, kwargs 

>>> x(3, 4, 5, b=6) 
TypeError: x() got multiple values for keyword argument 'b' 

Там еще один способ, но не то, что для чтения, чтобы иметь значения по умолчанию для аргументов и не имеют позиционных арг:

def x(*args, **kwargs): 
    kwargs.updae({'a': 1, 'b': 2}) 

Ваша функция, анализирует аргументы в порядке, хотя я не понимаю, почему вы пишете varargs и keywords в _.Он передает аргументы прозрачно:

def x(a = 1, b = 2, *args, **kwargs): 
    print a, b, args, kwargs 

def y(*args, **kwargs): 
    x(*args, **kwargs) 

>>> y(3, 4, 5, 6) 
3 4 (5, 6) {} 

>>> y(3, 4, 5, b=6) 
TypeError: x() got multiple values for keyword argument 'b' 
0

Я нашел ваше хорошее решение может немного быть улучшено, если принять во внимание, что общая функция теоретически может вернуть итератор, в этом случае выдается ошибка.

Вот решение для этого:

Wrap print 'return: %s' % ret в, если заявление:
if hasattr(ret, "__iter__"): print 'returned iterable' else: print 'return: %s' % ret

Таким образом, вы не использовать либо много времени печати больших итерируемых, но которые, конечно, могут быть изменены в соответствии с потребностями. (Также строка не имеет атрибута __iter__, что удобно)

Смежные вопросы