以编程方式从列表中定义静态方法
Define static methods from list programmatically
我有一个带有基本方法 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 or 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')
好多了,但是这个窗台看起来很乱。更多的 linters 仍然无法帮助您解决函数和属性名称中的拼写错误。所有 linter 都知道,Logger.info
和 Logger.inf
.
一样都是错字
使用 mako,您可以编写如下模板文件:
<%
levels = 'debug', 'info'
%>
class Logger:
% for level in levels:
@staticmethod
def ${level}(text):
log.log(text, ${repr(level)})
% endfor
这里模板的丑陋之处被模板文件捕获,生成的代码看起来就像正常的、完全表达的代码。
我有一个带有基本方法 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 or 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')
好多了,但是这个窗台看起来很乱。更多的 linters 仍然无法帮助您解决函数和属性名称中的拼写错误。所有 linter 都知道,Logger.info
和 Logger.inf
.
使用 mako,您可以编写如下模板文件:
<%
levels = 'debug', 'info'
%>
class Logger:
% for level in levels:
@staticmethod
def ${level}(text):
log.log(text, ${repr(level)})
% endfor
这里模板的丑陋之处被模板文件捕获,生成的代码看起来就像正常的、完全表达的代码。