У меня есть объект с базовым методом log(text, level), список levels, и я вручную определяю каждый метод следующим образом:
@staticmethod
def <level>(text):
log.log(text, '<level>')
(Где <level> должен быть заменен одним из элементов списка)
Как я мог сделать это программно?
Кроме того, мой список levels на самом деле является словарем, а <level> — ключом, но я знаю, как его перебрать.
также посмотрите на атрибуты python.






Вы можете использовать подобную функцию setattr для каждого уровня, обратите внимание на использование функции-оболочки staticmethod.
for level in LOG_TYPES:
setattr(A, level, staticmethod(lambda text, level=level: log.log(text, level)))
Обновлено:
Вы должны добавить level=level в объявление лямбда, иначе все лямбды ссылаются на один и тот же level, который назначен последним.
Пробовал, все заработало, кроме '<level>' внутри определения функции. Как я могу получить к нему доступ вне определения функции?
Я пробовал это: for level in LOG_TYPES: setattr(log, level, staticmethod(lambda text: log.log(text, level))) И он всегда использует последний элемент моего списка LOG_TYPES, независимо от определенной функции:/
Если вы хотите сгенерировать код, используйте что-то вроде мако или Джиндзя. Вы хотите, чтобы генерация вашего кода и фактический код, который выполняется вашей программой, были разделены. В основном это связано с тем, что код, сгенерированный на 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
Здесь уродство шаблона заключено в файле шаблона, а сгенерированный код выглядит как обычный, полностью выраженный код.
А) модуль
loggingимеет именно это и б) методы определяются там вручную по уважительным причинам (см. PEP-20).