Python OOP only initialise object if function arguments are met - python

How would I only allow an object to be created if the arguments are met? I tried using error handling but the object still gets created regardless of the value inputted.
class Age(object):
def __init__(self, age):
try:
if age > 5:
self.testAge = age
else:
raise ValueError('Number is too low')
except ValueError as exp:
print(f"Error: {exp}")
def __str__(self):
return f"Testing"
test = Age(3)
print(test)
In the example, I only want an object to be created if the Age is greater than 5. I use 3 as a test, the error is handled but the object is still created.

When you raise the exception, you except it again
You can either remove the try/except or re-raise the Exception
try:
function_which_may_raise()
except Exception as ex:
print("something went wrong")
raise ex # re-raise Exception

Related

failed: exceptions must derive from BaseException

I am trying to avoid the BaseException issue here . My requirement is i have a custom exception . when the custom exception is raised, i need to do some commands and need to abort a job.
class custom_exp(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return repr(self.msg)
try:
#calculating a threshold value
# if( above threshold):
raise custom_exp("hello")
except custom_exp as x:
# have some code to store the bad records
raise(message) # this line written to fail the job
except Exception as e:
# have some code to store the bad records
raise(str(e)) # this line written to fail the job
here is the output
File "C:\Users\gopia\OneDrive - VW Credit\Desktop\untitled1.py", line 11, in <module>
raise(message)
TypeError: exceptions must derive from BaseException
You could do something like this
class CustomExp(Exception):
pass
try:
# calculating a threshold value
# if above threshold:
raise CustomExp("hello")
except CustomExp as e:
# store the records
raise e
except Exception as e:
# store the records
raise e

How can I catch an exception raised inside of a catch clause, If the finally clause corresponding to the catch clause contains a return statement?

Suppose that:
TEF is a try-except-finally block.
an exception is raised from within the try clause of TEF
The finally clause, F of block T contains a return statement
TEF contains an except clause E
an exception e is raised inside of E
How can we catch e from outside of clause F and outside of clause E?
If that was confusing, then some code is shown below:
def e():
out = "hello world"
try:
raise ValueError("my name is Sarah")
except BaseException as exc:
# HOW DO I CATCH THE FIRST OF THE FOLLOWING
# exceptions from outside of this, current,
# except clause?
raise ValueError("secret info it would be good to know")
raise AttributeError
raise type("Hell", (Exception,), dict())()
[0, 1, 2][99999]
class AnythingYouCanThinkOf(Exception):
pass
raise AnythingYouCanThinkOf
out = "definitely not `hello world`"
finally:
return out
print(e())
print("No error!!! wowza!")
The code above prints:
hello world
No error!!! wowza!
If we comment out the line out = "hello world" then we get UnboundLocalError: local variable 'out' referenced before assignment. However, I am still not sure how to recover ValueError("secret info it would be good to know")
Also, if you put almost the same code outside of the function e, you get very different results. Why?
if True:
out = "hello world"
try:
raise ValueError("my name is Bob")
except BaseException as exc:
# HOW DO I CATCH THE FIRST OF THE FOLLOWING
# exceptions from outside of this, current,
# except clause?
raise ValueError("what is this madness?")
class AnythingYouCanThinkOf(Exception):
pass
raise AnythingYouCanThinkOf
out = "definitely not `hello world`"
finally:
print(out)
The above results in unhandled exception ValueError: what is this madness? before, we got No error!!! wowza!

Pass variable to an exception?

I am trying to learn Python and I want to know if it is possible to pass a variable to an Exception? This is the code I have:
try:
staffId = int(row['staffId'])
openingSalary = int(row['initialSalary'])
monthsWorked = float(row['monthsWorked'])
except CutomException:
pass
class CustomException(ValueError): # raised if data conversion fails
def __init__(self):
print("There was a problem converting data")
I want to pass staffId to the exception so that I can print something like:
print("There was a problem converting data for staff Id: ", staffId)
I tried this with no success: How to pass a variable to an exception when raised and retrieve it when excepted?
The caller of the exception, e.g. the one that raise exception will have to pass an argument to the constructor.
class CustomException(ValueError): # raised if data conversion fails
def __init__(self, message):
self.message = message;
print("There was a problem converting data")
try:
try:
staffId = int(row['staffId'])
openingSalary = int(row['initialSalary'])
monthsWorked = float(row['monthsWorked'])
except ValueError as e:
raise CustomException(e);
except CustomException:
pass
The custom exception will need to be raise'd conditionally by the try block to include the staffId variable. As an example, when the staffId is a str and not an int.
try:
# conditionalize a scenario where you'd want to raise an error
# (e.g. the variable is a string)
if type(staffId) is str:
raise CustomException(staffId)
else:
staffId = int(row['staffId'])
openingSalary = int(row['initialSalary'])
monthsWorked = float(row['monthsWorked'])
except CutomException:
pass
class CustomException(ValueError): # raised if data conversion fails
def __init__(self, id):
print("There was a problem converting data %s" % id)
I think you should handle the exception in the except block and not inside the exception class.
try:
raise CustomException(foo)
except CutomException as e:
print(e.args)
handle_exception()
class CustomException(Exception):
def __init__(self, foo):
super().__init__(foo, bar)

What is the right exception for an unmet precondition?

What is the appropriate exception to raise in a function to signal that a precondition was not met?
Examples:
def print_stats(name, age):
if name is None:
raise Exception("name cannot be None")
if not type(name) is str:
raise Exception("name must be a string")
if age is None:
raise Exception("age cannot be None")
if age < 0:
raise Exception("age cannot be negative")
print("{0} is {1} years old".format(name, age))
You should use both TypeError and ValueError.
The first three exceptions should be TypeErrors because we are signaling that the arguments are of an incorrect type. From the docs:
exception TypeError
Raised when an operation or function is applied to an object of
inappropriate type. The associated value is a string giving details
about the type mismatch.
The last exception however should be a ValueError because age is the correct type but has an incorrect value (it is negative). From the docs:
exception ValueError
Raised when a built-in operation or function receives an argument that
has the right type but an inappropriate value, and the situation is
not described by a more precise exception such as IndexError.
I also think you should use TypeError and ValueError but you can also improve the way you apply your preconditions.
Some time ago I was playing with postconditions and preconditions. Python allows you to write a much more elegant solution using decorators instead those if statements inside the function.
For instance:
def precondition(predicate, exception, msg): // 1
def wrapper(func):
def percond_mechanism(*args, **kwargs): // 2
if predicate(*args, **kwargs):
return func(*args, **kwargs) // 3
else:
raise exception(msg) // 4
return percond_mechanism
return wrapper
The condition, the exception you want to raise if the condition is not fulfilled and the message you want to show.
This part check if the condition is fulfilled.
If everething is ok, just return the result of the original funcion.
If not, raise the exception you pass with your message.
Now you can write your function like this:
#precondition(lambda name, age: name is not None, ValueError, "name can't be None")
#precondition(lambda name, age: type(name) is str, TypeError, "name has to be str")
# You can continue adding preconditions here.
def print_stats(name, age):
print("{0} is {1} years old".format(name, age))
This way is much more easier to read what can and can't be done. And actualy, you can use this precondition decorator in any function you want to.
I would go with ValueError:
Raised when a built-in operation or function receives an argument that
has the right type but an inappropriate value, and the situation is
not described by a more precise exception such as IndexError.
Source: https://docs.python.org/2/library/exceptions.html
I like Raydel Miranda's answer using decorator pre-conditions for the function. Here is an somewhat similar approach that, instead of decorators, uses introspection and eval. It would be less efficient, but arguably slightly more concise and expressive.
import inspect
class ValidationError(ValueError):
pass
def validate(assertion, exc=ValidationError, msg=''):
"""
Validate the given assertion using values
from the calling function or method. By default,
raises a `ValidationException`, but optionally
raises any other kind of exeception you like.
A message can be provided, and will be formatted
in the context of the calling function. If no
message is specified, the test assertion will be
recapitulated as the cause of the exception.
"""
frame = inspect.currentframe().f_back
f_locals, f_globals = frame.f_locals, frame.f_globals
result = eval(assertion, f_globals, f_locals)
if result:
return
else:
if msg:
msg = msg.format(**f_locals)
else:
msg = 'fails test {0!r}'.format(assertion)
raise(exc(msg))
def r(name):
validate('isinstance(name, str)', msg='name must be str (was {name!r})')
validate('name.strip() != ""', msg='name must be non-empty (was {name!r})')
print(name,)
def r2(name, age):
validate('isinstance(name, str)', TypeError, 'name must be str (was {name!r})')
validate('name.strip() != ""', ValueError, 'name must be non-empty (was {name!r})')
validate('isinstance(age, int)', TypeError, 'age must be int (was {age!r})')
validate('age >= 0', ValueError, 'age must be non-negative (was {age!r})')
print(name,)
r('Joe')
r('')
r2('Dale', -3)
r2('Dale', None)
This will raise exceptions such as:
ValidationError: name must be non-empty (was '')
Also nice: If you don't specify any message, it still gives reasonable output. For example:
def r2simple(name, age):
validate('isinstance(name, str)')
validate('name.strip() != ""')
validate('isinstance(age, int)')
validate('age >= 0')
print(name,)
r2simple('Biff', -1)
Yields:
ValidationError: fails test 'age >= 0'
This will work under either Python 2 or 3.

What does except really do in Python?

I'm really new in Python and a have no experience with exceptions but I've read all the documentation and couldn't find an answer ... so I'm looking for a deeper view in except's semantics.
When we have for example:
try:
x = 2
except GreaterThanOne:
print("The value is greater than one")
In this case I want the message to be printed.Is there a way for the GreaterThanOne class(exception) to be defined to raise when the entered value is greater than one ?
Ok, let me be more specific ...
Every error raises by a specific rule which should be add in the error attributes, am I right ?
For example:
try:
myvalue = x / y
except ZeroDivisionError:
print("Some error message printed ...")
So when I use this code and enter for y to be 0 the exception ZeroDivisionError will raise ... Can I for example redefine ZeroDivisionError to raise like this but if y is set to be ... 2 or 3 or any other value ?
Input:
x = 10
y = 2
try:
myvalue = x / y
except ZeroDivisionError:
print("division by 2")
Output: division by 2
Here's an example that should help you understand. Run this in your Python interpreter and watch how the exception is raised and caught (or not caught) when you call set_val(2).
# Defining our Exception subclass:
class GreaterThanOne(Exception):
pass
# The global value we pretend to care about:
val = 0
# Function to set a value but possibly raise our new Exception
def set_val(new_val):
if new_val > 1:
raise GreaterThanOne("%d > 1" % new_val)
val = new_val
# Catching exception:
try:
set_val(0)
set_val(1)
set_val(2)
except GreaterThanOne:
print "Whoops - one of those values was greater than one"
# Not catching exception:
set_val(0)
set_val(1)
set_val(2)
set_val(3)
an try-except block catches exception in this block.
try:
#some stuff here
except ExceptionClass as e:
#Exception handling here
the class after the except keyword indicates which kind of exception you want to catch. Usually you give a specific class, like ValueError or KeyError. You can also use the Exception class, to catch any exception. Because all the other exceptionclasses inhert from Exception.
so if you want to use this construct, an exception needs to be raised, Either by a function / method you call, or you raise it yourself with the raise keyword.
like this:
try:
raise KeyError('Just for test')
except KeyError as e:
#Exception handling here
The try except doesn't automagically inspect the whole code between it, it just looks for exceptions... Or to be more specific, it looks for those exceptions you tell it to look for.
Of course you can also inspect the exception instance.
try:
raise KeyError('Just for test')
except KeyError as e:
print e.args
For more information, please see:
http://docs.python.org/2/tutorial/errors.html

Categories

Resources