如何根据名称在全局范围内创建函数,以同名方式调用方法

时间:2014-10-28 14:50:00

标签: python logging dry python-2.6

我试图根据函数范围内logging.Logger实例的相应方法生成一堆函数。我感兴趣的功能/方法是:

['debug', 'info', 'warning', 'error', 'critical', 'exception']

所有人都拥有相同的原型。

现在我可以明确说明:

global debug, info, warning, error critical, exception

然后继续def每个人。我查了一下,这很好用。问题是我必须重复自己。

所以我有一个logging.Logger名为mylog的实例,它已经是全球性的。以下是我想要的,但分别通过硬编码函数/方法的名称:

global debug
def debug(msg, *args, **kwargs):
    if mylog: mylog.debug(msg, *args, **kwargs)

为了简洁起见,我将编写我的示例,只考虑debug,跳过其余部分。不幸的是,真正的代码有点复杂,因此使用lambda的要求似乎得以实现(单一陈述,对吧?)。

所以我明显的想法是在getattr上使用名称为"debug"的{​​{1}},并简单地调用我在已定义函数中返回的内容,并将其按名称添加到mylog 1}} globals()。例如:

dict

但是我认为这实际上并不合法,因为我称这是一个类方法,就像它是一个静态方法一样。然而,这"起作用",但每个输出行后跟另一行说for fct in ['debug']: def x(msg, *args, **kwargs): if mylog: getattr(mylog, fct)(msg, *args, **kwargs) globals()[fct] = x

所以我想我可以将实例作为第一个参数传递。完成None之后的所有内容:

self

给了我:

for fct in ['debug']:
    def x(msg, *args, **kwargs):
        if mylog: getattr(mylog, fct)(mylog, msg, *args, **kwargs)
    globals()[fct] = x

这与我从中获得的效果相同:

TypeError: not all arguments converted during string formatting

我根据这个问题的接受答案:Dynamically bind method to class instance in python

应用Alex Martelli here的答案会产生同样的错误。

我做错了什么?如何在不重复自己的情况下实现理想的行为?


完整追溯:

for fct in ['debug']:
    import types
    def x(msg, *args, **kwargs):
        if mylog: types.MethodType(getattr(mylog, fct), mylog)(msg, *args, **kwargs)
    globals()[fct] = x

完整脚本,基于上面的第一个示例代码:

Traceback (most recent call last):
  File "/usr/lib64/python2.6/logging/__init__.py", line 776, in emit
    msg = self.format(record)
  File "/usr/lib64/python2.6/logging/__init__.py", line 654, in format
    return fmt.format(record)
  File "/usr/lib64/python2.6/logging/__init__.py", line 436, in format
    record.message = record.getMessage()
  File "/usr/lib64/python2.6/logging/__init__.py", line 306, in getMessage
    msg = msg % self.args
TypeError: not all arguments converted during string formatting

1 个答案:

答案 0 :(得分:1)

在我看来,这应该有效:

debug = mylog.debug

或:

debug, info, warning, error, critical, exception = (
    mylog.debug, mylog.info, mylog.warning, 
    mylog.error, mylog.critical, mylog.exception)

动态设置:

for fct in ('debug', 'info', 'warning'):
    globals()[fct] = getattr(mylog, fct)

您的for循环for fct in ('debug'):正在遍历字符串'debug',您需要一个逗号for fct in ('debug',):才能使其成为元组。

还要注意构造如:

for fct in ['debug']:
    def x(msg, *args, **kwargs):
        if mylog: getattr(mylog, fct)(msg, *args, **kwargs)
    globals()[fct] = x

定义函数在调用时使用`fct``的当前值。您需要额外的间接级别来处理多个日志记录方法。 e.g。

def make_log(fct):
    def x(msg, *args, **kwargs):
        if mylog: getattr(mylog, fct)(msg, *args, **kwargs)
    return x

for fct in ['debug','info']:
    globals()[fct] = make_log(fct)