Регистрация методов с декоратором на уровне класса - PullRequest
0 голосов
/ 17 сентября 2018

Я бы хотел иметь возможность регистрировать / возвращать методы на уровне класса. Самый близкий ответ, который я мог найти, был здесь: Авторегистрация методов класса с использованием декоратора , за исключением того, что он был центрирован на глобальном регистре, и я ищу что-то конкретное для класса, описанного ниже.

Код:

class ExampleClass:

    def get_reports(self):
        # return list of all method names with @report decorator 
        pass

    def report(self):
        # decorator here
        pass

    @report
    def report_x(self):
        return

    @report
    def report_y(self):
        return

    def method_z(self):
        pass

где я бы хотел ExampleClass.get_reports() вернуть ['report_x', 'report_y'].

Не всем отчетам будет предшествовать report_, поэтому, скорее всего, нет способа просто посмотреть на имена методов. Я пытаюсь выяснить, как это сделать, чтобы применить к различным ситуациям, поэтому просто поиск 'report_' не работает в этом контексте.

Ответы [ 2 ]

0 голосов
/ 17 сентября 2018

Это похоже на ответ Mach_Zero . Таким образом, ключевые различия, это возвращает методы, а не имена методов, и реализация get_reports() несколько проще с использованием __iter__.

Код:

class Reports:

    def __init__(self):
        self.reports = []

    def __call__(self, func):
        self.reports.append(func)
        return func

    def __iter__(self):
        return iter(self.reports)


class ExampleClass:

    report = Reports()

    @classmethod
    def get_reports(cls):
        # return list of all method names with @report decorator
        return list(cls.report)

    @report
    def report_x(self):
        return

    @report
    def report_y(self):
        return

    def method_z(self):
        pass

Тестовый код:

print(ExampleClass.get_reports())

Результаты:

[
    <function ExampleClass.report_x at 0x000000000AF7B2F0>, 
    <function ExampleClass.report_y at 0x000000000AF7B378>
]
0 голосов
/ 17 сентября 2018

Вы можете объявить класс Reporter следующим образом и использовать экземпляр в качестве свойства класса. Я использовал переопределение __call__ для сокращения декоратора, но вы можете назвать функцию report и методы декорации как @report.report

class Reporter:
    def __init__(self):
         # Maintain a set of reported methods
        self._reported = set()

    def __call__(self, fn, *args, **kwargs):
        # Register method
        self._reported.add(fn.__name__)
        def decorate(*args, **kwargs):
            return fn(*args, **kwargs)
        return decorate    

class ExampleClass:
    report = Reporter()

    def get_reports(self):
         # return list of all method names with @report decorator 
         return list(self.report._reported)

    @report
    def report_x(self):
        return

    @report
    def report_y(self):
        return

    def method_z(self):
        pass
...