Определить статические методы из списка программно - PullRequest
0 голосов
/ 30 января 2019

У меня есть объект с базовым методом log(text, level), список levels, и я вручную определяю каждый метод следующим образом:

@staticmethod
def <level>(text):
     log.log(text, '<level>')

(где <level> - этобыть заменен одним из элементов списка) Как я могу сделать это программно?

Кроме того, мой список levels на самом деле является диктом, а ключ <level> является ключом, но я знаю, как перебиратьчто.

Ответы [ 2 ]

0 голосов
/ 30 января 2019

Если вы хотите сгенерировать код, используйте что-то вроде mako или jinja .Вы хотите сохранить генерацию своего кода и фактический код, который ваша программа работает отдельно.Это происходит главным образом потому, что код, сгенерированный в python, намного более расстраивает отладку.

Например, в Python вы можете сгенерировать ваш код следующим образом:

from textwrap import dedent

class Logger:
    for level in ('debug', 'info'):
        exec(dedent("""
            @staticmethod
            def {level}(text):
                log.log(text, {level!r})
        """.format(level=level)))

Logger.info('test')

Но тогда в исключении ваш стектрассировка будет сбивать с толку, например.

Traceback (most recent call last):
  File "C:\Users\User\Documents\python\a.py", line 18, in <module>
    Logger.info('test')
  File "<string>", line 4, in info <-- what is <string> and where can you find it?
NameError: name 'log' is not defined

Вместо этого вы можете попробовать:

class Logger:
    def gen_log_func(level):
        def _log(text):
            log.log(text, level)
        _log.__name__ = level
        return _log

    for level in ('debug', 'info'):
        locals()[level] = staticmethod(gen_log_func(level))

    del gen_log_func

Logger.info('test')

Лучше, но этот подоконник выглядит довольно грязно.Дальнейшие линтеры все еще не могут помочь вам с опечатками в именах функций и атрибутов.Все, что знает Линтер, Logger.info - это такая же опечатка, как и Logger.inf.

С помощью mako вы можете написать файл шаблона следующим образом:

<%
    levels = 'debug', 'info'
%>
class Logger:
    % for level in levels:
    @staticmethod
    def ${level}(text):
        log.log(text, ${repr(level)})

    % endfor

Здесь уродствошаблона захвачен внутри файла шаблона, и сгенерированный код выглядит просто как обычный, полностью выраженный код.

0 голосов
/ 30 января 2019

Вы можете использовать setattr функцию, подобную этой, для каждого уровня, обратите внимание на использование staticmethod функции-оболочки.

for level in LOG_TYPES:
    setattr(A, level, staticmethod(lambda text, level=level: log.log(text, level)))

РЕДАКТИРОВАТЬ: Вы должны добавить level=level в лямбда-декларации, в противном случае все лямбдыобращайтесь к тому же level, который является последним назначенным.

...