Как использовать Python декораторы для оптимизации написания различных методов, которые выполняют похожую работу? - PullRequest
1 голос
/ 05 марта 2020

Я новичок в Python и мне нужна помощь в декораторах. Я пишу несколько методов, которые вызывают другие методы, которые генерируются с использованием Swagger. В основном все эти чванливые методы имеют GET API. Все, что мне нужно сделать в моем коде, это вызвать эти методы и вернуть значение. Я ищу способы оптимизировать это вместо того, чтобы писать один и тот же метод для каждого API. Я сталкивался с декораторами, которые можно использовать в этом случае. Но моя реализация не дает желаемого результата

def get_component_info(self, func):
    def inner():
        data = None
        try:
            ret = func()
            if ret.status == 200:
                log.info('ret ' + str(ret))
            else:
                logging.error('Error: ' + str(ret.text))
        except Exception as e:
            logging.error(" failed with error " + str(e.reason) +
                            " and error code " + str(e.status))
        finally:
            return data
    return inner()

def get_firewall_info(self):
    return self._monitor.list_firewall_monitors_with_http_info()     <-- swagger method

def get_firewall_info_caller(self):
    get_firewall_info = self.get_component_info(self.get_firewall_info())

Но приведенная выше реализация всегда возвращает None, потому что она никогда не выполняет self._monitor.list_firewall_monitors_with_http_info(), но тест не завершается

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

Спасибо

Ответы [ 2 ]

1 голос
/ 05 марта 2020

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

def decorator(func):
    def inner(*args, **kwargs):
        # Do stuff here...
        value = func(*args, **kwargs)
        # ...or here.
        return value
    return inner

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

    def get_component_info(self, func):
        def inner():
            # ...
        return inner

    def get_firewall_info_caller(self):
        # You will now want to call the `inner` function after you get
        # it from `get_component_info`.
        get_firewall_info = self.get_component_info(...)()

Похоже, суть вашей ошибки в том, что вы не предоставляете функцию для get_component_info; вы предоставляете результат вызова этой функции. Я думаю, что изменение кода, чтобы не вызывать get_firewall_info, должно исправить ваш код.


    def get_firewall_info_caller(self):
        # You don't want to call the function you're providing to a
        # decorator, since it's expecting the function not the result.
        get_firewall_info = self.get_component_info(self.get_firewall_info)()
0 голосов
/ 06 марта 2020

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

def get_component_info(self, func):
    def inner():
        data = None
        try:
            ret = func()
            if ret.status == 200:
                log.info('ret ' + str(ret))
            else:
                logging.error('Error: ' + str(ret.text))
        except Exception as e:
            logging.error(" failed with error " + str(e.reason) +
                            " and error code " + str(e.status))
        finally:
            return data
    return inner

def get_firewall_info(self):
    data = self.get_component_info(self._monitor.list_firewall_monitors_with_http_info)()
    return data
...