Why am I getting different results for the following two code snippets (Python 3.4):
class MainError(Exception):
def __init__(self, msg, **parms):
super().__init__()
self.msg = msg
self.parms = parms
print('Parms original', parms)
def __str__(self):
return self.msg + ':' + str(self.parms)
class SubError(MainError):
def __init__(self, msg, **parms):
super().__init__(msg, **parms)
try:
raise SubError('Error occured', line = 22, col = 11)
except MainError as e:
print(e)
>>>
Parms original {'line': 22, 'col': 11}
Error occured:{'line': 22, 'col': 11}
And:
class MainError(Exception):
def __init__(self, msg, **args):
super().__init__()
self.msg = msg
self.args = args
print('Parms original', args)
def __str__(self):
return self.msg + ':' + str(self.args)
class SubError(MainError):
def __init__(self, msg, **args):
super().__init__(msg, **args)
try:
raise SubError('Error occured', line = 22, col = 11)
except MainError as e:
print(e)
>>>
Parms original {'line': 22, 'col': 11}
Error occured:('line', 'col')
It's because the error args are overwritten, by converting them to a Python tuple at the C level.
Here is the BaseException class for Python: https://hg.python.org/cpython/file/tip/Objects/exceptions.c
Starting at line 31, we see the following:
Likewise, the init call has the same tuple conversion:
In short, self.args is getting converted to a tuple which is converted back to a string, which causes the difference.
The BaseException class is called for (I believe) all the method wrappers as a required argument.
This is appreciable if pass it a non-iterable argument (such as an integer):
Moral of the story: Don't name your variables words that are constantly redefined and are key terms for the class you are using.