我有一个带有基方法log(text, level)
的对象,一个levels
列表,我手动定义每个方法,如下所示:
@staticmethod
def <level>(text):
log.log(text, '<level>')
(其中<level>
将替换为列表的项目之一)如何以编程方式执行此操作?
另外,我的levels
列表实际上是一个字典,<level>
是关键,但我知道如何迭代它。
级别使用这样的setattr
函数,请注意使用staticmethod
包装器函数。
for level in LOG_TYPES:
setattr(A, level, staticmethod(lambda text, level=level: log.log(text, level)))
编辑:您必须在 lambda 声明中添加level=level
,否则所有 lambda 都引用相同的level
,这恰好是最后一个分配的。
如果你想生成代码,那么使用像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:UsersUserDocumentspythona.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')
更好,但这个门槛看起来很乱。进一步的 linters 仍然无法帮助您解决函数和属性名称中的拼写错误。众所周知,Logger.info
和Logger.inf
一样是一个错字。
使用 mako,您可以编写如下模板文件:
<%
levels = 'debug', 'info'
%>
class Logger:
% for level in levels:
@staticmethod
def ${level}(text):
log.log(text, ${repr(level)})
% endfor
在这里,模板的丑陋被捕获在模板文件中,生成的代码看起来就像正常的、完全表达的代码。