在Python中使用format()方法打印布尔值True/False

22 投票
1 回答
22003 浏览
提问于 2025-04-18 06:32

我在尝试打印布尔表达式的真值表时,遇到了一些有趣的事情:

>>> 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() 方法得到的结果是一样的。非空的格式字符串通常会修改结果。

所以,当你使用格式说明符时,字符串的内容会被修改。但如果只指定了一个对齐操作符(例如 ^),为什么会从 True 变成 1 呢?

1 个回答

9

这个问题问得很好!我觉得我知道答案。要找到答案,我们需要看看Python的源代码,里面是用C语言写的,所以请耐心点。

首先,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',谜底就解开了!

撰写回答