2017-01-30 3 views
0

В настоящее время у меня есть декоратор, который обертывает функцию в класс.Использование декоратора, возвращающего класс по методу?

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

Этот декоратор отлично работает над функциями вне классов. Однако при использовании его с методами аргумент self уже неявно передается, и я не уверен, почему.

Вот лучший пример, который я не мог собрать

from __future__ import print_function 

import functools 


def test_wrap(func): 
    @functools.wraps(func) 
    def wrapper(*args, **kwargs): 
     print("Args:", args) 
     print("Kwargs:", kwargs) 
     func(*args, **kwargs) 
    return wrapper 


def test_class_wrap(func): 
    """Return a Command object for use with the custom framework we are using.""" 
    @functools.wraps(func, assigned=('__name__', '__module__'), updated=()) 
    class Command(object): 
     def __init__(self, *args, **kwargs): 
      print("Args:", args) 
      print("Kwargs:", kwargs) 
      func(*args, **kwargs) 

    return Command 


class MyObject(object): 

    def __init__(self): 
     self.value = 100 

    @test_wrap 
    def foo(self): 
     print(self.value) 

    @test_class_wrap 
    def bar(self): 
     print(self.value) 


if __name__ == '__main__': 
    obj = MyObject() 
    obj.foo() 

    print() 
    obj.bar(obj) # works 
    # obj.bar() # TypeError: bar() takes exactly 1 argument (0 given) 
    # Why is self implicitly passed as an argument like with outher methods? 

# Output 
# Args: (<__main__.MyObject object at 0x7fe2bf9bb590>,) 
# Kwargs: {} 
# 100 

# Args: (<__main__.MyObject object at 0x7fe2bf9bb590>,) 
# Kwargs: {} 
# 100 
+0

Хорошо. , , подумайте, как это будет работать, если вы сделали это вручную. Без декоратора вы пишете код, в котором один класс вложен внутри другого? Если да, то как вы это сделали? Классы - это не методы, поэтому, если у вас есть декоратор, который заменяет метод классом, у вас будет класс внутри вашего другого класса, что несколько необычно для Python. Можете ли вы показать пример того, как вы будете писать «MyObject» и «bar» вручную », не используя декоратор? – BrenBarn

+0

Этот вопрос более сфокусирован на том, почему 'self' неявно передается' bar'. Приведенный выше код реплицирует проблему, а не фактическое использование. Я могу попытаться добавить пример, но не ожидаю, что это будет иметь смысл. – Shatnerz

+0

Причина self не передана, потому что нет экземпляра вашего класса. 'self' относится к экземпляру, поэтому его можно передавать только при вызове метода в экземпляре, но ваш' obj.bar' является * классом *, называемым 'Command'. Если вы написали этот класс Command отдельно и попытались вызвать 'Command()', вы получите ту же ошибку. – BrenBarn

ответ

1

test_class_wrap делает ничего, просто возвращает класс так __init__ не называется. Попробуйте обернуть класс функцией, передающей аргументы и kwargs:

def test_class_wrap(func): 
    """Return a Command object for use with the custom framework we are using.""" 
    @functools.wraps(func, assigned=('__name__', '__module__'), updated=()) 
    def wrapper(*args, **kwargs): 
     class Command(object): 
      def __init__(self, *args, **kwargs): 
       print("Args:", args) 
       print("Kwargs:", kwargs) 
       func(*args, **kwargs) 
     return Command(*args, **kwargs) 
    return wrapper 

... 

if __name__ == '__main__': 
    obj = MyObject() 
    obj.foo() 

    print() 
    obj.bar() 
+0

Я думаю, это может «исправить», но неясно, как это сделать. Это просто означает, что 'obj.bar()' возвращает класс Command, тогда как теперь значение 'obj.bar' является классом Command. Поэтому 'obj.bar()' ничего не сделает "; он просто вернет класс. – BrenBarn

+0

Я уверен, что это именно то, что мне нужно. Он также передает все мои существующие тесты. @BrenBarn Целью был экземпляр класса при вызове 'bar()'. Его дрянной, неочевидный дизайн, но я не очень много говорю об изменении его. Вот почему я пытаюсь обернуть все и облегчить дело. – Shatnerz

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