Применение декоратора ко всем методам производного подкласса - PullRequest
0 голосов
/ 21 января 2020

У меня есть специфический c класс, который является довольно общим, и я хочу получить другой класс, где команда запускается перед методами класса.

Путь, который я выбрал, основан на на { ссылка }. Я пробовал много другого, но чувствовал, что понимаю, как это работает. Ну, здесь я тоже был неправ. Насколько я понимаю, процесс выглядит следующим образом: 1) создать подкласс, 2) получить все вызываемые методы базового класса, 3) перезаписать эти методы их оформленной версией.

Мой код:

from functools import wraps, partial

def deco_func(func): #, channel):      
    @wraps(func)
    def new_function(*args,**kwargs):
        print("Decorator func.")
        return func(*args,**kwargs)                
    return new_function  

print("checking the operation of the decorator function")
def sq(a):
    print(a**2)
sq2 = deco_func(sq)
sq(1.1)
sq2(1.3) # yep, sq2 works


class my_class():
    def __init__(self, a):
        self.a = a
    def square(self):
        self.a = self.a**2
        print(self.a)

class my_subclass(my_class):
    def __init__(self, func, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # go over all elements in my_class and if it is callable, apply the
        # decorator function
        for attr_name in my_class.__dict__:
            attr = getattr(self, attr_name)
            if callable(attr) and a:
                print("Callable method found: %r" % attr_name)
                setattr(self, attr_name, partial(func, attr))

class my_subclass2(my_class):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # go over all elements in my_class and if it is callable, apply the
        # decorator function
        for attr_name in my_class.__dict__:
            attr = getattr(self, attr_name)
            if callable(attr) and a:
                print("Callable method found: %r" % attr_name)
                setattr(self, attr_name, partial(deco_func, attr))


print("\nOriginal class:")
a = my_class(1.05)
a.square()
a.square()
print("Supposed to be 1.05^4: %r" % a.a)
print("\nFirst subclass version:")
b = my_subclass(a=1.07, func=deco_func)
b.square()
b.square()
print("Supposed to be 1.07^4: %r" % b.a)
print("\nSecond subclass version:")
c = my_subclass2(a=1.03)
c.square()
c.square()
print("Supposed to be 1.03^4: %r" % c.a)

Вывод:

checking the operation of the decorator function
1.2100000000000002
Decorator func.
1.6900000000000002

Original class:
1.1025
1.21550625
Supposed to be 1.05^4: 1.21550625

First subclass version:
Callable method found: '__init__'
Callable method found: 'square'
Supposed to be 1.07^4: 1.07

Second subclass version:
Callable method found: '__init__'
Callable method found: 'square'
Supposed to be 1.03^4: 1.03

Проблема в том, что b.square() и c.square() возвращают функциональный объект, но я не понимаю, почему. Я ожидаю, что c .square () будет таким же, как deco_fun c (my_class.square ()), то есть sq2 (). Очевидные вопросы: где я ошибаюсь, почему декорированная функция класса возвращает другую функцию и как я могу преодолеть эту проблему?

Я использую python 3.6.9.

1 Ответ

0 голосов
/ 21 января 2020

Каким-то образом функция part () нарушает код Ниже MWE, который работает. К сожалению, я не смог добавить аргумент в декоратор, но я могу жить с этим на данный момент.

from functools import wraps, partial
import inspect, types

def deco_func(func):       
    @wraps(func)
    def new_function(*args,**kwargs):
        print("Decorator func.")
        return func(*args,**kwargs)                
    return new_function  

class my_class():
    def __init__(self, a):
        self.a = a
    def square(self):
        self.a = self.a**2
        print(self.a)

class my_subclass(my_class):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        for attr_name in my_class.__dict__:
            attr = getattr(self, attr_name)
            if callable(attr) and attr_name[0:2] != "__":
                print("Callable method found: %r" % attr_name)
                setattr(self, attr_name, deco_func(attr))


print("\nOriginal class:")
a = my_class(1.02)
a.square()
a.square()
print("Supposed to be 1.02^4=1.082: %r" % a.a)

print("\nSubclass version:")
b = my_subclass(a=1.01)
b.square()
b.square()
print("Supposed to be 1.01^4=1.04: %r" % b.a)
...