以编程方式定义列表中的静态方法



我有一个带有基方法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.infoLogger.inf一样是一个错字。

使用 mako,您可以编写如下模板文件:

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

在这里,模板的丑陋被捕获在模板文件中,生成的代码看起来就像正常的、完全表达的代码。

最新更新