Странности с self.args при работе с объектами типа "исключение"
Анализируя работу с исключениями, наткнулся на вот такую ситуацию. Берем пример который в разных видах гуляет по источникам и учебникам:
class UppercaseException(Exception):
pass
words = ['я', 'ты', 'он', 'ОНА', 'оно']
for word in words:
if word.isupper():
raise UppercaseException (word)
Результат получаем ожидаемый:
Traceback (most recent call last):
File "<ipython-input-54-fc1eb7bb7c0c>", line 4, in <module>
raise UppercaseException (word)
UppercaseException: ОНА
Ввожу конструктор класса. На случай, если мне в дальнейшем потребуется некоторая обработка в нем - ввожу определение нового атрибута:
class UppercaseException ( Exception ):
def __init__(self, ar):
print ('Обработка исключений')
self.atr = ar
return
words = ['я', 'ты', 'он', 'ОНА', 'оно']
for word in words:
if word.isupper():
raise UppercaseException (word)
Результат практически тождественен предыдущему:
Обработка исключений
Traceback (most recent call last):
File "<ipython-input-55-b239d3ebd306>", line 10, in <module>
raise UppercaseException (word)
UppercaseException: ОНА
Пока все понятно и ожидаемо. А теперь - собственно вопрос. Изменяю имя атрибута:
class UppercaseException ( Exception ):
def __init__(self, ar):
print ('Обработка исключений')
self.args = ar
return
words = ['я', 'ты', 'он', 'ОНА', 'оно']
for word in words:
if word.isupper():
raise UppercaseException (word)
И результат меняется кардинально!
Обработка исключений
Traceback (most recent call last):
File "<ipython-input-56-6460513f725f>", line 9, in <module>
raise UppercaseException (word)
UppercaseException: ('О', 'Н', 'А')
Для облегчения анализа вывожу типы (ну и по ходу - сами значения) внутри конструктора
class UppercaseException ( Exception ):
def __init__(self, ar):
print ('Входной параметр: ', type(ar),ar)
self.args = ar
print ('Атрибут класса: ', type(self.args),self.args)
return
words = ['я', 'ты', 'он', 'ОНА', 'оно']
for word in words:
if word.isupper():
raise UppercaseException (word)
Обратите внимание как определяются типы:
Входной параметр: <class 'str'> ОНА
Атрибут класса: <class 'tuple'> ('О', 'Н', 'А')
Traceback (most recent call last):
File "<ipython-input-64-448db16a8ad8>", line 10, in <module>
raise UppercaseException (word)
UppercaseException: ('О', 'Н', 'А')
Я даже могу предположить, что это как-то связано с тем, что класс UppercaseException наследуется от класса Exception. Но и это как-бы не должно влиять на тип переопределяемого атрибута, причем даже если будет явно (!) вызываться конструктор класса-родителя (при неявном вызове - ситуация аналогичная) :
class A:
def __init__(self, a):
self.args = tuple(a)
print("class A: ",self.args,type(self.args))
class B(A):
def __init__(self, a):
super().__init__( a)
print("Параметр a :",a,type(a))
self.args = a
print("class B: ",self.args,type(self.args))
b=B('qwerty')
Результат:
class A: ('q', 'w', 'e', 'r', 't', 'y') <class 'tuple'>
Параметр a : qwerty <class 'str'>
class B: qwerty <class 'str'>
Тип как был строковым, так таким и остался, т.е. произошло именно переопределение. Как и ожидалось.
Может кто-то разбирался с этим вопросом, или имеет хоть какие-то предположение о том, что и почему происходит при работе с исключениями?
Ответы (1 шт):
Добавим и изменим пару строк:
def __init__(self, ar):
print ('На входе: ', type(self.args),self.args) # Здесь
print ('Входной параметр: ', type(ar),ar)
self.newAr = ar # И здесь
print ('Атрибут класса: ', type(self.newAr),self.newAr)
return
и получим
На входе: <class 'tuple'> ('ОНА',)
Входной параметр: <class 'str'> ОНА
Атрибут класса: <class 'str'> ОНА
args определятся в родительском классе как tuple. И при вашем присвоении происходит преобразование. Никаких чудес
exception BaseException
args
The tuple of arguments given to the exception constructor. Some built-in exceptions (like OSError) expect a certain number of arguments and assign a special meaning to the elements of this tuple, while others are usually called only with a single string giving an error message.