I want to include an except inside a class, but when I run the code, the except is returning an empty class object. How can I make the except return only the error message and nothing else?
class InputError(Exception):
"""Raised when input format not allowed"""
pass
class ReadMap1:
def __init__(self, input):
try:
if (type(input) == str) | (type(input) == int):
if type(input) == str:
self.input = input
else:
self.input = str(input)
else:
raise InputError
except InputError:
print("----Input not allowed----")
Output:
ReadMap1([1])
----Input not allowed----
<__main__.ReadMap1 object at 0x0000024B30B49FD0>
CodePudding user response:
Many people confuse Python's __init__
with constructors from other languages, because like a constructor, __init__
is often used to initialize attributes. However, __init__
is not a constructor, but an initializer. The distinction is subtle though not terribly complicated in practice: The constructor constructs and returns an object, hence you can do my_obj = ClassConstructor()
whereas the initializer only works on the object that the constructor already created. This is why Python's MyClass.__init__
returns nothing.
Your code is behaving as expected. You have told it:
if input is a string or integer, then do some stuff
if input is another type, then crash with InputError
if the above ever crashes with InputError, print an error message instead of crashing and move on
Then you pass the initializer [1]
which is a Python list
. This being neither a string nor a number, the interpreter raises an InputError
. Normally exceptions cause a crash, but since you have the try catch, the crash is then negated, and instead a message is printed.
You can "fix" this trivially by changing your except
clause to be like:
except InputError:
print("----Input not allowed----")
self.input = "default value"
It sounds like you want the initialization to be aborted in this case. Then you should remove the try-except
, and let __init__
crash. The caller will then have to create the object like so:
try:
rm = ReadMap1([1])
except InputError:
print("----Input not allowed----")
Or you could omit the try-except
here as well and allow the entire program to crash. It all depends: If input
was invalid, could you program a way for your program to keep ticking, or is everything lost regardless?
There some additional issues in your code:
input
is the name of a builtin function -- it's better to avoid shadowing it. Find a more unique name for your argument.- If you are going to check types in your
if
, you don't needtry
. You would eithertry
to use the value and handleexcept TypeError
, or you would useif type(...
, not both. - It makes little sense to
raise
an exception inside atry
that catches it.try
is useful when the exception may arise form somewhere deep inside the code you are calling, and it would be impractical to directly check for the problem. In this case it is evident that you can check the type yourself, instead of relying on exceptions, so just do that. - If you are merely converting the value to a string, you don't need to check the type at all. Just do
self.input = str(input)
. If it's already a string, Python will pass it unaltered. Everything else will be converted to a string (by calling the object's [or its parents'].__str__
method).
CodePudding user response:
You can define __new__()
in order to intercept the creation of the object. You can return None
here given a certain condition. Doing that will prevent __init__()
from being called.
class ReadMap:
def __new__(cls, input):
if (type(input) == str) | (type(input) == int):
return super().__new__(cls)
print("----Input not allowed----")
return None
def __init__(self, input):
self.input = input
o = ReadMap(1)
o.input
# 1
p = ReadMap([1])
# prints ----Input not allowed----
print(p)
# None
I suspect this isn't a great idea, but I don't know how you are using this. It's pretty unexpected for the caller to call ReadMap()
and get None
, but it is possible. In general, I would opt for raising and letting the caller deal with the bad input — they after all sent the bad input.