2012-03-12 2 views
3

Можно ли в Python 2,6-2,7 использовать тот же декоратор для следующей задачи:Python: украсить __call__ и обычную функцию с тем же декоратором?

class ComplextCallableObject(object): 
    @wrap_me 
    def __call__(self, a1, a2): 
     pass 

@wrap_me 
def simple_function(a1, a2): 
    pass 

Оба ComplextCallableObject.__call__ и simple_function имеют те же аргументы, но __call__ также self для первого арг. В декодере wrap_me мне нужен доступ для функции, которая обертывается args.

+0

Что должно выполняться 'wrap_me'? Как обе функции выполняют задачу 'wrap_me', если они принимают разные аргументы? –

ответ

2

К сожалению, во время определения (блок класса в этом случае) код не может определить, как будет использоваться функция, кроме как по соглашению об именах. Изменение вашего примера немного:

class ComplextCallableObject(object): 
    @wrap_me 
    def __call__(self, a1, a2): 
     pass #... 

@wrap_me 
def simple_function(tgt, a1, a2): 
    pass 

ComplextCallableObject.anInstanceMethod = simple_function 
ComplextCallableObject.anClassMethod = classmethod(simple_function) 
ComplextCallableObject.aStaticMethod = staticmethod(simple_function) 

В этом случае simple_function реализует функцию принятия цели и два параметра, метод экземпляра принимая два параметра, метод класса с двумя параметрами, а также статический метод, принимающей целью и два параметра. Но это использование не связано только после того, как функция определена. И staticmethod, и classmethod возвращают другой тип объекта, поэтому вы можете рассказать об этом, если потребуется.

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

def wrap_me(fn): 
    names = fn.func_code.co_varnames 
    if names and names[0]=='self': 
     print 'looks like an instance method' 
    else: print 'looks like a function' 
    return fn 
0
def wrap_me(*args): 
    a1, a2 = args if len(args) == 2 else args[1:] 
    ... 

Конечно, вам нужно будет изменить возвращаемую функцию взять self аргумент, если wrap_me был вызван метод класса, а также.

Кстати, если вы не используете self внутри функции, которую вы украшаете, это должен быть статический метод.

+0

Я использую 'self' в' __call__' (инициализирую тяжелый материал в '__init__' и использую его в' __call__'), когда я не использую 'self' в' __call__'. Я конвертирую эти объекты в простые функции – dmzkrsk

+0

Таким образом, «тот же» декоратор делает две разные вещи, в зависимости от того, вызван ли он методом или функцией? Почему бы не сделать два декоратора? – katrielalex

0

Это может быть довольно тупым, но может также работать хорошо для простейшего случая:

In [1]: def wrap_me(func): 
    ...:  def wrapped(*args): 
    ...:   print 'arg1 is', args[-2] 
    ...:   print 'arg2 is', args[-1] 
    ...:   func(*args) 
    ...:  return wrapped 
    ...: 
In [2]: class ComplexCallableObject(object): 
    ...:  @wrap_me 
    ...:  def __call__(self, a1, a2): 
    ...:   print 'class object called' 
    ...: 
In [3]: @wrap_me 
    ...: def simple_function(a1, a2): 
    ...:  print 'function called' 
    ...: 
In [4]: simple_function('A', 'B') 
arg1 is A 
arg2 is B 
function called 
In [5]: o = ComplexCallableObject() 
In [6]: o('A', 'B') 
arg1 is A 
arg2 is B 
class object called 
+0

К сожалению, я забыл ответ katrielalex, который по сути тот же. Я позволю ему повесить здесь для иллюстрации, если никто не возражает. –

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