Подтвердить что ты не робот

Печать логических значений True/False с помощью метода format() в Python

Я пытался распечатать таблицу истинности для булевых выражений. Выполняя это, я наткнулся на следующее:

>>> 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. Я знаю, что bool является подклассом int, поэтому True оценивается как 1:

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

Но почему в первом примере с помощью спецификатора формата изменяется 'True' на 1?

Я обратился к документам для уточнения. Единственное, что он говорит:

Общим соглашением является то, что пустая строка формата ("") дает тот же результат, что и вы набрали str() для значения. Непустая строка формата обычно изменяет результат.

Таким образом, строка изменяется, когда вы используете спецификатор формата. Но почему изменение от True до 1, если задан только оператор выравнивания (например, ^)?

4b9b3361

Ответ 1

Отличный вопрос! Я верю, что у меня есть ответ. Это требует копания через исходный код 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 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', и тайна закончилась!