Как объявить декоратор внутри класса, чтобы декорировать уже оформленный, унаследованный метод? - PullRequest
1 голос
/ 15 мая 2019

Я хочу создать декоратор, который является членом класса, и который будет украшать унаследованный метод, который декорируется.

пример кода:

class A(object):
    __metaclass__ = ABCMeta
    def __init__(self):
        pass

    @classmethod
    def the_decorator(cls, decorated):  # <-----this is what i want, with or without self/cls as an argument
        def decorator()
            #do stuff before
            decorated()
            print "decorator was called!"
            #do stuff after
        return decorator

    @abstractmethod
    def inherited():
        raise NotImplemented


class B(A):
    def __init__(self):
        super(B,self).__init__()

    #@A.the_decorator <--- this is what I want, 
    @overrides
    #@A.the_decorator <--- or this
    def inherited():
        print "B.inherited was invoked"

и

b = B()
b.inherited()

должен вывести

Был вызван B.inherited

Вызван декоратор!


Прочитав Это руководство по декораторам как членам класса , я до сих пор не смог выяснить, как декорировать унаследованные методы декораторами, определенными в суперклассе.


Обратите внимание, здесь @overrides - этоопределяется пакетом overrides pip install overrides


Также обратите внимание, что в настоящее время я использую Python 2.7, но хотел бы получить ответы как 2.7, так и 3+.

Спасибо!

Ответы [ 2 ]

2 голосов
/ 15 мая 2019

Вы были не так далеко!

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

Но этот код должен работать:

class A(object):
    __metaclass__ = ABCMeta
    def __init__(self):
        pass

    @staticmethod
    def the_decorator(decorated):  # <-----this is what i want, with or without self/cls as an argument
        def decorator(self):
            #do stuff before
            decorated(self)
            print "decorator was called!"
            #do stuff after
        return decorator

    @abstractmethod
    def inherited():
        raise NotImplemented


class B(A):
    def __init__(self):
        super(B,self).__init__()

    @A.the_decorator #<--- this is what I want, 
    @overrides
    #@A.the_decorator <--- or this
    def inherited(self):
        print "B.inherited was invoked"

Я мог бы протестировать его под Python 2.7 за исключением @overrides декоратор (я прокомментировал это в своих тестах)

0 голосов
/ 15 мая 2019

При использовании Python 3 вашему коду просто не хватает нескольких собственных аргументов, чтобы можно было вызывать функцию с помощью b.inherited ()

class A(object):
    __metaclass__ = ABCMeta
    def __init__(self):
        pass

    @classmethod
    def the_decorator(cls, decorated): 
        def decorator(*args, **kwargs):
            #do stuff before
            decorated(*args, **kwargs)
            print("decorator was called!")
            #do stuff after
        return decorator

    @abstractmethod
    def inherited(self):
        raise NotImplemented


class B(A):
    def __init__(self):
        super(B,self).__init__()

    @A.the_decorator
    @overrides
    def inherited(self):
        print("B.inherited was invoked")
...