Как определяется __str__ в пользовательском исключении?

На курсе я нашел следующий кусок кода:

class Ex(Exception):
    def __init__(self, msg):
        Exception.__init__(self, msg + msg)
        self.args = (msg,) 
try:
    raise Ex('ex')
except Ex as e:
    print(e)
except Exception as e:
    print(e)

Прочитав это, я подумал, что печать e покажет exex, но это только ex.

Разве msg + msg не должны изменить его на exex?

@Chris, потому что строка 3 дважды объединяет сообщения.

motionsickness 14.12.2020 04:07

Вы вручную устанавливаете .args на self.args = (msg,) Если вы удалите эту строку, она напечатает exex

juanpa.arrivillaga 14.12.2020 04:08

Кажется, что super().__init__(msg + msg) без возни с .args лучше шаблон.

Mark 14.12.2020 04:10

@juanpa.arrivillaga да, это было так. str задается args[0] (чего я не знал), и я не совсем понял, что следующая строка устанавливает args.

motionsickness 14.12.2020 04:21

@MarkMeyer, это просто пример, сделанный, чтобы запутать ученика. Что явно подействовало на меня.

motionsickness 14.12.2020 04:22

@motionsickness ну, нет, посмотрите на ответ, __str__ либо вернет пустую строку, если args является пустым кортежем, либо первый элемент, если это кортеж длины один, либо просто строковый кортеж, если это множественный -элементный кортеж

juanpa.arrivillaga 14.12.2020 04:24
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
6
80
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

BaseException.__str__ определяется здесь

static PyObject *
BaseException_str(PyBaseExceptionObject *self)
{
    switch (PyTuple_GET_SIZE(self->args)) {
    case 0:
        return PyUnicode_FromString("");
    case 1:
        return PyObject_Str(PyTuple_GET_ITEM(self->args, 0));
    default:
        return PyObject_Str(self->args);
    }
}

грубо переведено в псевдокод:

def __str__(self) -> str:
    if len(self.args) == 0:
        return ''
    elif len(self.args) == 1:
        return str(self.args[0])
    else:
        return str(self.args)

поэтому в этом случае, даже если вы инициализируете Exception.__init__ удвоением msg, вы сразу же забиваете self.args исходным значением

если вы print(self.args) до того, как назначите его, вы увидите свое двойное сообщение

если вы удалите задание self.args, вы получите ожидаемое значение

Другие вопросы по теме