Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
try/except blocks
#1
Hi!

I'm trying (no pun intended! Big Grin ) to understand the try/except blocks. I'm using this program, that returns "Error: Invalid argument.", when the division is tried to be done by zero:

def division1(divideBy):
    try:
        return 72 / divideBy
    except ZeroDivisionError:
        print(f'72 divided by 0 produces an Error: Invalid argument.')
        

print(f'72 divided by 2 is {division1(2)}.')
print(f'72 divided by 12 is {division1(12)}.')
print(f'72 divided by 0 is {division1(0)}.')
print(f'72 divided by 1 is {division1(1)}.')
that produces the following output:
Output:
72 divided by 2 is 36.0. 72 divided by 12 is 6.0. 72 divided by 0 produces an Error: Invalid argument. 72 divided by 0 is None. 72 divided by 1 is 72.0.
but I would like the line returning the value None not to appear in the output, like this:
Output:
72 divided by 2 is 36.0. 72 divided by 12 is 6.0. 72 divided by 0 produces an Error: Invalid argument. 72 divided by 1 is 72.0.
How could I do it? I mean, of course, not dividing by zero, but I want just the program to say that that would produce an error due to an invalid argument.

Thanks in advance.

All the best,
newbieAuggie2019

"That's been one of my mantras - focus and simplicity. Simple can be harder than complex: You have to work hard to get your thinking clean to make it simple. But it's worth it in the end because once you get there, you can move mountains."
Steve Jobs
Reply
#2
def division1(divideBy):
    try:
        return 72 / divideBy
    except ZeroDivisionError:
        return
"As they say in Mexico 'dosvidaniya'. That makes two vidaniyas."
https://freedns.afraid.org
Reply
#3
you should add the raise statement after handling the ZeroDivisionError, otherwise you will never see additional exceptions
def division1(divideBy):
    try:
        return 72 / divideBy
    except ZeroDivisionError:
        print(f'72 divided by 0 produces an Error: Invalid argument.')
        raise
 
print(f'72 divided by 2 is {division1(2)}.')
print(f'72 divided by 12 is {division1(12)}.')
print(f'72 divided by 0 is {division1(0)}.')
print(f'72 divided by 1 is {division1(1)}.')
Reply
#4
(Oct-05-2019, 02:36 AM)wavic Wrote:
def division1(divideBy):
    try:
        return 72 / divideBy
    except ZeroDivisionError:
        return

Thank you!

Your answer is much closer and nicer to what I want. The output is:
Output:
72 divided by 2 is 36.0. 72 divided by 12 is 6.0. 72 divided by 0 is None. 72 divided by 1 is 72.0.
while I would prefer for the 3rd division to appear as '72 divided by 0 produces an Error: Invalid argument.', because in layman's terms, it explains what produces and why.

'72 divided by 0 is None.' in layman's terms, it means '72 divided by 0 is 0.', which is misguiding:
Output:
72 divided by 2 is 36.0. 72 divided by 12 is 6.0. 72 divided by 0 produces an Error: Invalid argument. 72 divided by 1 is 72.0.
Thanks again!

All the best,

(Oct-05-2019, 02:57 AM)Larz60+ Wrote: you should add the raise statement after handling the ZeroDivisionError, otherwise you will never see additional exceptions
def division1(divideBy):
    try:
        return 72 / divideBy
    except ZeroDivisionError:
        print(f'72 divided by 0 produces an Error: Invalid argument.')
        raise
 
print(f'72 divided by 2 is {division1(2)}.')
print(f'72 divided by 12 is {division1(12)}.')
print(f'72 divided by 0 is {division1(0)}.')
print(f'72 divided by 1 is {division1(1)}.')

Thank you!

Probably, I'm not very good at explaining. My apologies! The program I had, already warned with the message '72 divided by 0 produces an Error: Invalid argument.', but also included an extra line saying '72 divided by 0 is None.' that I don't like it, and I wish I could find a way to avoid it.

Your suggestions produce the following output:
Output:
72 divided by 2 is 36.0. 72 divided by 12 is 6.0. 72 divided by 0 produces an Error: Invalid argument.
Error:
Traceback (most recent call last): File "C:/Users/User1/AppData/Local/Programs/Python/Python37/atbs_03_zeroDivide_02_BIS_03.py", line 10, in <module> print(f'72 divided by 0 is {division1(0)}.') File "C:/Users/User1/AppData/Local/Programs/Python/Python37/atbs_03_zeroDivide_02_BIS_03.py", line 3, in division1 return 72 / divideBy ZeroDivisionError: division by zero
that is precisely what I'm trying to avoid by using the try/except block.

Thanks again!

All the best,
newbieAuggie2019

"That's been one of my mantras - focus and simplicity. Simple can be harder than complex: You have to work hard to get your thinking clean to make it simple. But it's worth it in the end because once you get there, you can move mountains."
Steve Jobs
Reply
#5
What you actually try to do in this case is to customize the error message. You should re-raise the exception with your custom message

def division1(divideBy):
    try:
        return 72 / divideBy
    except ZeroDivisionError:
        raise ZeroDivisionError('72 divided by 0 produces an Error: Invalid argument.')

for n in (2, 12, 0, 1):
    try:
        print(f'72 divided by {n} is {division1(n)}.')
    except ZeroDivisionError as zde:
        print(zde)
Output:
72 divided by 2 is 36.0. 72 divided by 12 is 6.0. 72 divided by 0 produces an Error: Invalid argument. 72 divided by 1 is 72.0.
of course what you would really do is
for n in (2, 12, 0, 1):
    try:
        print(f'72 divided by {n} is {72 / n)}.')
    except ZeroDivisionError:
        print ('72 divided by 0 produces an Error: Invalid argument.')
If you like/need you may wrap it as function
def divide72(divisor):
    try:
        print(f'72 divided by {n} is {72 / divisor)}.')
    except ZeroDivisionError:
        print ('72 divided by 0 produces an Error: Invalid argument.')
for n in (2, 12, 0, 1):
    divide72(n)
I understand though that this function is just an example
In other words, you should propagate the error from your function and catch it when you call the function.

Of course there might be cases when you just want to catch the error (e.g. in mid loop) print some message and continue the execution of the function/loop
If you can't explain it to a six year old, you don't understand it yourself, Albert Einstein
How to Ask Questions The Smart Way: link and another link
Create MCV example
Debug small programs

Reply
#6
The code that uses a function must take into account the specifications of that function. When you design the function, you need to say what the function does when it receives invalid parameters. What are the possibilities?
  1. raise an exception (the type of the exception can be fine-tuned)
  2. return a value that indicates an error (can be None)
  3. return a dummy value
  4. return an unspecified value
What are the options for the client code?
  1. Ignore the error which includes letting an exception or a faulty value propagate
  2. Detect the error and take appropriate action
I think the good strategy is often 1. for the function's design and 1. for the exploiting code. Strategy 1 is usually possible for the client code only if the function's design chose strategy 1. Using strategy 2 in the client code means that this code needs to test return values or catch exceptions as Buran said.

Note that there could be more exotic design option, for example the function could set a global indicator to say that it failed, but this is not relevant in a language that implements exceptions. It is the strategy used in the C implementation of python with the PyErr_SetString() and PyErr_Occurred() functions but that's another story.
Reply
#7
(Oct-05-2019, 07:57 AM)buran Wrote: What you actually try to do in this case is to customize the error message.

Yeah, thank you! You're completely right! You express yourself better than I do!!!

(Oct-05-2019, 07:57 AM)buran Wrote: You should re-raise the exception with your custom message
Please, bear with me. Some concepts are easier for me to handle, while others (even being simpler) make me think of myself as rather thick ... Cry
I'm not quite sure what exactly these technical terms mean.

Ok, so:

Errors detected during execution are called exceptions.

And in this context, the technical expression 'to raise an exception' means 'to mention something for somebody to discuss or to deal with' and not as I wrongly thought, 'to end a restriction on somebody or something (like to raise a blockade, a ban, an embargo)', which would have meant here, to let the 'error detected during execution' go with no problems.

So, if I have understood correctly,

(Oct-05-2019, 07:57 AM)buran Wrote: You should re-raise the exception with your custom message

means to bring into attention again the error detected during execution, with my tailor-made message.

(Sorry, I'm always amazed at how our language means something completely different when applied to computing. Take 'argument' as an example ... Tongue ).
Output:
72 divided by 2 is 36.0. 72 divided by 12 is 6.0. 72 divided by 0 produces an Error: Invalid argument. 72 divided by 1 is 72.0.
Fantastic!!! That is EXACTLY what I wanted, and you made it possible!!! Thanks again!

As I am very thick and I wanted to understand what every little piece of code does, I ran separately these two bits of code (as programs, not as a line command):

for n in (2, 12, 0, 1):
    try:
        print(f'72 divided by {n} is {72 / n)}.')
    except ZeroDivisionError:
        print ('72 divided by 0 produces an Error: Invalid argument.')
and:

def divide72(divisor):
    try:
        print(f'72 divided by {n} is {72 / divisor)}.')
    except ZeroDivisionError:
        print ('72 divided by 0 produces an Error: Invalid argument.')
for n in (2, 12, 0, 1):
    divide72(n)
Both producing an:

Error:
SyntaxError: unexpected EOF while parsing.
I looked for it, and it seems that it is usually due to:
1) Missing something like a closing parenthesis (I checked, I copied and pasted it, and I also typed it again, and it doesn't seem to be the case).
2) The SyntaxError: unexpected EOF while parsing means that the end of your source code was reached before all code blocks were completed like a code block starting with a statement as 'for i in range(100):' and requiring at least one line afterwards that contains code that should be in it.

I'm more inclined to think that it is due to something related to the second reason, but still I don't see the reason for that Syntax Error. Am I doing something wrong again or am I missing something important in here?

Anyway, thanks a lot indeed for your great explanation and for solving my dilemma! I still don't fully understand it, but I guess with more learning and coding on my part, I'll do it sooner or later.

All the best,

(Oct-05-2019, 08:39 AM)Gribouillis Wrote: What are the options for the client code?
[ ... ]
It is the strategy used in the C implementation of python with the PyErr_SetString() and PyErr_Occurred() functions but that's another story.
I'm still a newbie, and have no previous programming background, so while I can do a few things here and there, I get lost at most of the technical jargon. Cry

I really do appreciate your time and effort trying to explain it to me. Thank you!

All the best,
newbieAuggie2019

"That's been one of my mantras - focus and simplicity. Simple can be harder than complex: You have to work hard to get your thinking clean to make it simple. But it's worth it in the end because once you get there, you can move mountains."
Steve Jobs
Reply
#8
I recommend to type help('try') and/or help('EXCEPTIONS') into Python interactive interpreter and enjoy wonderful world of built-in help (these topics are especially extensively covered). One can't be master of try..except unless he knows how to use else and finally as well.
I'm not 'in'-sane. Indeed, I am so far 'out' of sane that you appear a tiny blip on the distant coast of sanity. Bucky Katt, Get Fuzzy

Da Bishop: There's a dead bishop on the landing. I don't know who keeps bringing them in here. ....but society is to blame.
Reply
#9
there was extra bracket in both cases on line 3

for n in (2, 12, 0, 1):
    try:
        print(f'72 divided by {n} is {72 / n}.')
    except ZeroDivisionError:
        print ('72 divided by 0 produces an Error: Invalid argument.')
def divide72(divisor):
    try:
        print(f'72 divided by {n} is {72 / divisor}.')
    except ZeroDivisionError:
        print ('72 divided by 0 produces an Error: Invalid argument.')
for n in (2, 12, 0, 1):
    divide72(n)
sorry, it was my mistake
If you can't explain it to a six year old, you don't understand it yourself, Albert Einstein
How to Ask Questions The Smart Way: link and another link
Create MCV example
Debug small programs

Reply
#10
(Oct-05-2019, 05:01 PM)buran Wrote: there was extra bracket in both cases on line 3

[ ... ]

sorry, it was my mistake

Don't worry! I'm very much obliged to you!!!

I couldn't spot it myself, while managing it many times!!!

Wall I'm so thick! I'm so thick! I'm so thick! I'm so thick! I'm so thick! I'm so thick!

All the best,
newbieAuggie2019

"That's been one of my mantras - focus and simplicity. Simple can be harder than complex: You have to work hard to get your thinking clean to make it simple. But it's worth it in the end because once you get there, you can move mountains."
Steve Jobs
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  RSA Cipher with blocks Paragoon2 0 491 Nov-26-2023, 04:35 PM
Last Post: Paragoon2
  How to properly format rows and columns in excel data from parsed .txt blocks jh67 7 1,879 Dec-12-2022, 08:22 PM
Last Post: jh67
  Am I a retard - else and finally blocks in a try statement RubenF85 6 2,589 Jan-12-2021, 05:56 PM
Last Post: bowlofred
  How to tabulate correctly repeated blocks? Xiesxes 4 2,941 Mar-21-2020, 04:57 PM
Last Post: Xiesxes
  Understanding program blocks newbieAuggie2019 2 1,966 Oct-02-2019, 06:22 PM
Last Post: newbieAuggie2019
  The Empty List Blocks Recursion leoahum 6 5,320 Mar-05-2019, 06:55 PM
Last Post: leoahum

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020