web-dev-qa-db-ja.com

Pythonでformat()メソッドを使用してブール値True / Falseを出力する

ブール式の真理値表を印刷しようとしていました。これをしているときに、私は次のことに遭遇しました。

_>>> format(True, "") # shows True in a string representation, same as str(True)
'True'
>>> format(True, "^") # centers True in the middle of the output string
'1'
_

形式指定子を指定するとすぐに、format()Trueを_1_に変換します。 boolintのサブクラスであるため、Trueは_1_と評価されます。

_>>> format(True, "d") # shows True in a decimal format
'1'
_

しかし、なぜ最初の例でフォーマット指定子を使用すると_'True'_が_1_に変更されるのですか?

説明のためのドキュメント を参照しました。それが言う唯一のものは:

一般的な規則では、空のフォーマット文字列(_""_)は、値に対してstr()を呼び出した場合と同じ結果を生成します。空でないフォーマット文字列は通常、結果を変更します。

したがって、書式指定子を使用すると、文字列が変更されます。しかし、onlyアライメント演算子(例_1_)が指定されている場合に、Trueから_^_に変更される理由?

22

すばらしい質問です。私には答えがあると思います。これには、CのPythonソースコード)を掘り下げる必要があります。

まず、format(obj, format_spec)obj.__format__(format_spec)の構文糖衣です。特にこれが発生する場所については、関数で abstract.c を確認する必要があります。

_PyObject *
PyObject_Format(PyObject* obj, PyObject *format_spec)
{
    PyObject *empty = NULL;
    PyObject *result = NULL;

    ...

    if (PyInstance_Check(obj)) {
        /* We're an instance of a classic class */
HERE -> PyObject *bound_method = PyObject_GetAttrString(obj, "__format__");
        if (bound_method != NULL) {
            result = PyObject_CallFunctionObjArgs(bound_method,
                                                  format_spec,
                                                  NULL);

    ...
}
_

正確な呼び出しを見つけるには、 intobject.c を調べる必要があります。

_static PyObject *
int__format__(PyObject *self, PyObject *args)
{
    PyObject *format_spec;

    ...

    return _PyInt_FormatAdvanced(self,
                     ^           PyBytes_AS_STRING(format_spec),
                     |           PyBytes_GET_SIZE(format_spec));
               LET'S FIND THIS
    ...
}
_

__PyInt_FormatAdvanced_は実際には formatter_string.c のマクロとして formatter.h にある関数として定義されています:

_static PyObject*
format_int_or_long(PyObject* obj,
               STRINGLIB_CHAR *format_spec,
           Py_ssize_t format_spec_len,
           IntOrLongToString tostring)
{
    PyObject *result = NULL;
    PyObject *tmp = NULL;
    InternalFormatSpec format;

    /* check for the special case of zero length format spec, make
       it equivalent to str(obj) */
    if (format_spec_len == 0) {
        result = STRINGLIB_TOSTR(obj);   <- EXPLICIT CAST ALERT!
        goto done;
    }

    ... // Otherwise, format the object as if it were an integer
}
_

そしてそこにあなたの答えがあります。 _format_spec_len_が_0_かどうかを簡単にチェックし、そうであればobjを文字列に変換します。ご存知のように、str(True)は_'True'_であり、謎が解けました!

9
huu