2014-01-22 2 views
2

У меня есть набор функций/методов, у которых есть разные набор позиционных аргументов и, в некоторых случаях, аргументы с ключевыми словами, но разделяйте один строковый аргумент с именем lane_type. Это может быть либо позиционный, либо ключевой аргумент. Из-за дефекта дизайна (виноватого в качестве обвинения) одно и то же значение в разных местах может иметь заглавные буквы в строке. Поэтому для сравнения я должен преобразовать его в нижний регистр. В конце концов я решил попробовать и сделать преобразование через декоратор:Декоратор для функций с позиционными аргументами, с обычно называемым аргументом

def lt_dec(func): 
    def _lt_lower(**kwargs): 
     kwargs['lane_type'] = kwargs['lane_type'].lower() 
     return func(**kwargs) 
    return _lt_lower 

Конечно, я пытался проверить его - и это не удалось:

In [38]: @lt_dec 
def test1(lane_type): 
    print lane_type 
    ....:  

In [39]: test1('Solid') 
--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
/homes/markg/<ipython-input-39-bb6cef5c7fad> in <module>() 
----> 1 test1('Solid') 

TypeError: _lt_lower() takes exactly 0 arguments (1 given) 

Очевидно, что я не совсем понимаю, ** kwargs. Я буду очень благодарен за объяснение, чего у меня нет, и если есть изящное решение для моей проблемы.

EDIT:

Я считаю, что я должен показать некоторые примеры определений функций для ясности: Вот один метод из класса

def add_polygon(self, points, lane_type, color): 

метод из другого класса:

def __init__(self, points, lane_type, color, side=None): 

A функция

def lane_weight(lane_type): 

Конечно, для функции с 1 аргумента (у меня есть несколько из них) решение простое

def lt_dec(func): 
    def _lt_lower(lane_type): 
     return func(lane_type) 
    return _lt_lower 

Как есть уже говорилось выше, - это есть общее решение, которое для всех примеров показали? (Я готов принять Нет, как ответ)

+0

«решение прост» - да? этот код ничего не делает ... –

ответ

4

Использование **kwargs в определении функции, вы получите именованные аргументы (не позиционные аргументы) в качестве словаря:

>>> def lt_dec(func): 
...  def _lt_lower(**kwargs): 
...   print 'type(kwargs)=', type(kwargs) 
...   print 'kwargs=', kwargs 
...   kwargs['lane_type'] = kwargs['lane_type'].lower() 
...   return func(**kwargs) 
...  return _lt_lower 
... 
>>> @lt_dec 
... def test1(lane_type): 
...  print lane_type 
... 
>>> test1(lane_type='Solid') 
type(kwargs)= <type 'dict'> 
kwargs= {'lane_type': 'Solid'} 
solid 

>>> def lt_dec(func): 
...  def _lt_lower(*args, **kwargs): 
...   if args: 
...    args = (args[0].lower(),) + args[1:] 
...   elif 'lane_type' in kwargs: 
...    kwargs['lane_type'] = kwargs['lane_type'].lower() 
...   return func(*args, **kwargs) 
...  return _lt_lower 
... 
>>> @lt_dec 
... def test1(lane_type): 
...  print lane_type 
... 
>>> test1('Solid') 
solid 
>>> test1(lane_type='Solid') 
solid 

UPDATE

Использование inspect.getcallargs:

>>> import inspect 
>>> 
>>> def lt_dec(func): 
...  def _lt_lower(*args, **kwargs): 
...   kwargs = inspect.getcallargs(func, *args, **kwargs) 
...   if 'lane_type' in kwargs: 
...    kwargs['lane_type'] = kwargs['lane_type'].lower() 
...   return func(**kwargs) 
...  return _lt_lower 
... 
>>> @lt_dec 
... def test1(blah, lane_type): 
...  print lane_type 
... 
>>> test1('foo', 'Solid') 
solid 
>>> test1('foo', lane_type='Solid') 
solid 
+0

спасибо, но это не решает мою общую проблему. Может быть, нет общих решений? – volcano

+0

@volcano Ваша проблема будет устранена этим ответом, не могли бы вы рассказать о своей общей проблеме, в вопросе? – thefourtheye

+0

@volcano, я добавил код, который обрабатывает как позиционные, так и ключевые аргументы. Это то, что вы хотите? – falsetru

0

Это вариант декоратора, который уменьшает влияние инспектировать используя его во время украшения - и не в то время выполнения. Эффект исполнения по-прежнему относительно высок - но в 100 раз ниже, чем в оригинальном декораторе, который вы предложили (только FYI)

def lane_type_lower(func): 

    def _conv_pos(*args, **kwargs): 
     args = list(args); 
     args[pos] = args[pos].lower() 
     return args, kwargs 

    def _conv_kw(*args, **kwargs): 
     kwargs['lane_type'] = kwargs['lane_type'].lower() 
     return args, kwargs 

    insp = inspect.getargspec(func) 
    try: 
     pos = insp.args.index('lane_type') 
     conv_func = _conv_pos 
    except ValueError: 
     conv_func = _conv_kw 

    def _lane_type_lower(*args, **kwargs): 
     args, kwargs = conv_func(*args, **kwargs) 
     return func(*args, **kwargs) 

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