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」関数は実際にはクラスのバインドされたメソッドですが、それは表示されません。私が達成しようとしているのは、関数がバインドされたメソッドである場合、代わりに次の形式で出力することです。

「###モジュール->クラス名.関数」

しかし、問題は次のとおりです。

  1. スタックから関数を取得するだけなので、バインドされたメソッドかどうかを実際に確認することはできません
  2. 関数参照があったとしても、それがバインドされているクラス名をどのように推測するのでしょうか?

これを理解するのに役立つ回答をありがとう。

4

1 に答える 1

5

これは簡単だと思っていましたが、少し複雑であることがわかりました。バインドされたメソッドへの参照がある場合は、 を介してそのクラス名を取得できますboundMethod.im_class.__name__。ただし、スタックを取得しているときは、フレームをスタックするためだけに、バインドされたメソッドへの参照を簡単に取得できません。

しかし、すべてが失われるわけではありません!モジュールは、関数inspectを使用してスタック フレームから関数の引数を取得できますgetargvalues。メソッドには常に「self」という名前の最初の引数があるという慣習に頼って、少しごまかす必要があります。それを確認してから、関数の辞書から「自己」値localsを取得すると、そこからクラス名を簡単に取得できます。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 に答える