2016-07-21 2 views
1

Я никогда не понимал обработку исключений в Python (или любой язык, если честно). Я экспериментировал с пользовательскими исключениями и нашел следующее поведение.Внедрение `Exception .__ str __()` в Python

class MyError(Exception): 
    def __init__(self, anything): 
     pass 

me = MyError("iiiiii") 
print(me) 

Выход:

iiiiii 

Я полагаю, что print() звонки Exception.__str__().

Каким образом базовый класс Exception знает для печати iiiiii? Строка "iiiiii" была передана конструктору MyError по аргументу anything, но anything не хранится нигде в MyError вообще!

Кроме того, конструктор MyError не вызывает конструктор своего суперкласса (исключение). Итак, как print(me) печать iiiiii?

+1

Какая версия Python? Это невозможно воспроизвести в Python 2.7. –

+0

Извините, забыл упомянуть, Python 3.5.1. – Ray

ответ

1

В Python 3, BaseException класс имеет __new__ метод, который хранит аргументы в self.args:

>>> me.args 
('iiiiii',) 

Вы не переопределять __new__ метод, только __init__. Вы должны были бы переопределить как, чтобы полностью предотвратить от self.args быть установлен, так как обе реализации счастливо установить этот атрибут:

>>> class MyError(Exception): 
...  def __new__(cls, *args, **kw): 
...   return super().__new__(cls) # ignoring args and kwargs! 
...  def __init__(self, *args, **kw): 
...   super().__init__()   # again ignoring args and kwargs 
... 
>>> me = MyError("iiiiii") 
>>> me 
MyError() 
>>> print(me) 

>>> me.args 
() 

В Python 2, исключения не осуществлять __new__ и ваш образец ничего не печатать бы. См. issue #1692335 о том, почему был добавлен метод __new__; в основном, чтобы избежать таких проблем, как ваш, где метод __init__ также не вызывает super().__init__().

Отметьте, что __init__ не является конструктором ; экземпляр уже построен к тому времени, на __new__. __init__ - это просто инициализатор .

+0

Релевантная проблема: https://bugs.python.org/issue1692335 – vaultah