2011-07-05 4 views
5

Для декоратора, который я пишу, я хотел бы манипулировать определенным именованным параметром функции. Рассмотрим следующий декоратор:Как я могу рассматривать позиционные аргументы как аргументы ключевого слова в Python 2

def square_param(param): 
    def func_decorator(func): 
     def func_caller(*args,**kwargs): 
      kwargs[param] = kwargs[param] * kwargs[param] 
      return func(*args,**kwargs) 
    return func_caller 
return func_decorator 

Applied на следующей функции:

@square_param('dividend') 
def quotient(divisor=1,dividend=0): 
    return dividend/divisor 

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

>>> quotient(dividend=2) 
4 

Однако, когда дается как позиционный аргумент, это не сработает.

>>> quotient(3,4) 
TypeError: quotient() got multiple values for keyword argument 'dividend' 

С Python 3 я мог бы решить эту проблему, заставляя параметр быть always given as a keyword:

@square_param('dividend') 
def quotient(divisor=1,*,dividend=0): 
    return dividend/divisor 

, но я хотел бы поддержать Python 2, а также я хотел бы поставить в небольшие ограничения на функции ,

Есть ли способ, которым я могу исправить это поведение в моем декораторе?

+3

Осмотрите инспектировать модуль. У этого может быть то, что вам нужно. Посмотрите на getargspec. – Dirk

ответ

3

Во-первых, ваш декоратор square_param не работает, потому что он не возвращает функции. Она должна быть:

def square_param(param): 
    def func_decorator(func): 
     def func_caller(*args,**kwargs): 
      kwargs[param] = kwargs[param] * kwargs[param] 
      return func(*args,**kwargs) 
     return func_caller 
    return func_decorator 

Теперь я взял @ совет Дирка и заглянул в inspect модуль. Вы можете сделать это, сначала проверив, является ли параметр одним из позиционных аргументов функции, и вторым, если этот позиционный аргумент указан, а затем изменил эту позицию аргумента. Вам также необходимо убедиться, что вы только модифицируете kwargs, если параметр был поставлен как аргумент ключевого слова.

import inspect 

def square_param(param): 
    def func_decorator(func): 
     def func_caller(*args,**kwargs): 
      funparams = inspect.getargspec(func).args 
      if param in funparams: 
       i = funparams.index(param) 
       if len(args) > i: 
        args = list(args) # Make mutable 
        args[i] = args[i] * args[i] 
      if param in kwargs: 
       kwargs[param] = kwargs[param] * kwargs[param] 
      return func(*args,**kwargs) 
     return func_caller 
    return func_decorator 
+0

Спасибо, это именно то, что я искал! О возврате функций, это была действительно небольшая глупая ошибка, сделанная в этом примере. –

2

даже без использования Осмотреть мы можем получить функцию Params

>>> func = lambda x, y, args: (x, y, {}) 
>>> func.func_code.co_argcount 
3 
>>> func.func_code.co_varnames 
('x', 'y', 'args') 
+0

Спасибо! Не могли бы вы добавить ссылку, в которой зарегистрированы элементы func_code? Я не могу этого найти. –

+0

Добро пожаловать! «func_code - это объект кода, представляющий скомпилированное тело функции». Более подробную информацию вы можете найти в разделе «Вызываемые типы» в [link] (http://docs.python.org/reference/datamodel.html). – Yajushi