5

我有一个很棒的小功能,看起来像这样:

def verbose_print(message, *args, **kwargs):
    """Prints `message` with a helpful prefix when in verbose mode

    Args:
        message (str): The message to print. Can be a format string, e.g.
            `A %s with some %s in it`
        *args: Variables for the message format
        **kwargs: Keyword variables for the message format
    """

    # Only print when in verbose mode
    if not config.verbose:
        return

    # Ready a prefix for the message
    try:
        s = inspect.stack()
        module_name = inspect.getmodule(s[1][0]).__name__
        func_name = s[1][3]
        prefix = '### %s->%s' % (module_name, func_name)
    except Exception as e:
        prefix = '### [stack unavailable]'

    if args:
        message = message % args
    elif kwargs:
        message = message % kwargs

    print '%s: %s' % (prefix, message)

该函数的重点是我可以从任何地方通过消息调用它,如果我的项目配置文件设置为详细模式,所有消息都将打印一个有用的前缀以显示它被调用的位置。这是一些输出的示例:

### avesta.webserver->check_login: 检查客户端在 127.0.0.1 的登录
### avesta.webserver->check_login:找到用户名:tomas,令牌:blablabla 的凭据 cookie
### avesta.webserver->check_login: 登录有效,刷新会话
### avesta.webserver->get_flash_memory:获取的闪存数据:无
### avesta.webserver->get:从空路径('previous_values','name')获取数据,返回''
### avesta.webserver->get:从空路径('previous_values','description')获取数据,返回''
### avesta.webserver->get:从空路径('validation_errors','name')获取数据,返回''

格式为"### module->function: message"

现在大多数时候这确实很有帮助,但并不完美。在上面的例子中,“get”函数实际上是一个类的绑定方法,但它是不可见的。我想要完成的是,当一个函数是一个绑定方法时,我用这种格式打印:

“### 模块->ClassName.function”

但问题是:

  1. 我只从堆栈中获取函数,所以我无法真正检查它是否是绑定方法
  2. 即使我有函数引用,我将如何推断它绑定的类名?

感谢您提供任何可以帮助我解决这个问题的答案。

4

1 回答 1

5

我以为这会很容易,但结果有点复杂。如果你有对绑定方法的引用,你可以通过boundMethod.im_class.__name__. 但是,当你抓取堆栈时,你不能轻易获得对绑定方法的引用,只是为了堆栈帧。

然而,一切都没有丢失!该inspect模块可以使用该getargvalues函数从堆栈框架中获取函数参数。您确实必须通过依赖方法总是将其第一个参数命名为“self”的约定来作弊。你可以检查一下,然后从函数的locals字典中获取“self”值,然后从那里很容易得到类名。尝试用他的代码替换你当前的try块:

s = inspect.stack()
module_name = inspect.getmodule(s[1][0]).__name__
func_name = s[1][3]
arginfo = inspect.getargvalues(s[1][0])
if len(arginfo.args) > 0 and arginfo.args[0] == "self":
    func_name = "%s.%s" (arginfo.locals["self"].__class__.__name__, func_name)
prefix = '### %s->%s' % (module_name, func_name)
于 2012-07-29T00:23:31.963 回答