How can I ignore ZeroDivisionError and make n / 0 == 0?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
Check if the denominator is zero before dividing. This avoids the overhead of catching the exception, which may be more efficient if you expect to be dividing by zero a lot.
def weird_division(n, d):
return n / d if d else 0
Method 2
You can use a try/except block for this.
def foo(x,y):
try:
return x/y
except ZeroDivisionError:
return 0
>>> foo(5,0)
0
>>> foo(6,2)
3.0
Method 3
I think try except (as in Cyber’s answer) is usually the best way (and more pythonic: better to ask forgiveness than to ask permission!), but here’s another:
def safe_div(x,y):
if y == 0:
return 0
return x / y
One argument in favor of doing it this way, though, is if you expect ZeroDivisionErrors to happen often, checking for 0 denominator ahead of time will be a lot faster (this is python 3):
import time
def timing(func):
def wrap(f):
time1 = time.time()
ret = func(f)
time2 = time.time()
print('%s function took %0.3f ms' % (f.__name__, int((time2-time1)*1000.0)))
return ret
return wrap
def safe_div(x,y):
if y==0: return 0
return x/y
def try_div(x,y):
try: return x/y
except ZeroDivisionError: return 0
@timing
def test_many_errors(f):
print("Results for lots of caught errors:")
for i in range(1000000):
f(i,0)
@timing
def test_few_errors(f):
print("Results for no caught errors:")
for i in range(1000000):
f(i,1)
test_many_errors(safe_div)
test_many_errors(try_div)
test_few_errors(safe_div)
test_few_errors(try_div)
Output:
Results for lots of caught errors: safe_div function took 185.000 ms Results for lots of caught errors: try_div function took 727.000 ms Results for no caught errors: safe_div function took 223.000 ms Results for no caught errors: try_div function took 205.000 ms
So using try except turns out to be 3 to 4 times slower for lots of (or really, all) errors; that is: it is 3 to 4 times slower for iterations that an error is caught. The version using the if statement turns out to be slightly slower (10% or so) when there are few (or really, no) errors.
Method 4
Solution
When you want to efficient handle ZeroDivisionError (division by zero) then you should not use exceptions or conditionals.
result = b and a / b or 0 # a / b
How it’s works?
- When
b != 0we haveTrue and a / b or 0.True and a / bis equal toa / b.a / b or 0is equal toa / b. - When
b == 0we haveFalse and a / b or 0.False and a / bis equal toFalse.False or 0is equal to0.
Benchmark
Timer unit: 1e-06 s
Total time: 118.362 s
File: benchmark.py
Function: exception_div at line 3
Line # Hits Time Per Hit % Time Line Contents
==============================================================
3 @profile
4 def exception_div(a, b):
5 100000000 23419098.5 0.2 19.8 try:
6 100000000 40715642.9 0.4 34.4 return a / b
7 100000000 28910860.8 0.3 24.4 except ZeroDivisionError:
8 100000000 25316209.7 0.3 21.4 return 0
Total time: 23.638 s
File: benchmark.py
Function: conditional_div at line 10
Line # Hits Time Per Hit % Time Line Contents
==============================================================
10 @profile
11 def conditional_div(a, b):
12 100000000 23638033.3 0.2 100.0 return a / b if b else 0
Total time: 23.2162 s
File: benchmark.py
Function: logic_div at line 14
Line # Hits Time Per Hit % Time Line Contents
==============================================================
14 @profile
15 def logic_div(a, b):
16 100000000 23216226.0 0.2 100.0 return b and a / b or 0
Method 5
def foo(x, y):
return 0 if y == 0 else x / y
Method 6
I think if you don’t want to face Zer0DivErrr, you haven’t got to wait for it or go through it by using try-except expression. The quicker way is to jump over it by making your code simply not to do division when denominator becomes zero:
(if Y Z=X/Y else Z=0)
Method 7
You can use the following :
x=0,y=0 print (y/(x or not x))
Output:
>>>x=0 >>>y=0 >>>print(y/(x or not x)) 0.0 >>>x =1000 >>>print(y/(x or not x)) 0.000999000999000999
not x will be false if x is not equal to 0, so at that time it divides with actual x.
Method 8
If you are trying to divide two integers you may use :
if y !=0 :
z = x/y
else:
z = 0
or you can use :
z = ( x / y ) if y != 0 else 0
If you are trying to divide two lists of integers you may use :
z = [j/k if k else 0 for j, k in zip(x, y)]
where here, x and y are two lists of integers.
Method 9
I was intrigued why ToTomire‘s solution would be faster. If feels like conditional_div should often be preferred for its natural language readability, but if I can understand exactly why logic_div is faster that might help me in the future. I looked to python’s dis for this.
>>> conditional_div = lambda n,d: n/d if d else 0
>>> logic_div = lambda n,d: d and n/d or 0
>>> dis.dis(conditional_div)
1 0 LOAD_FAST 1 (d)
2 POP_JUMP_IF_FALSE 12
4 LOAD_FAST 0 (n)
6 LOAD_FAST 1 (d)
8 BINARY_TRUE_DIVIDE
10 RETURN_VALUE
>> 12 LOAD_CONST 1 (0)
14 RETURN_VALUE
>>> dis.dis(logic_div)
1 0 LOAD_FAST 1 (d)
2 POP_JUMP_IF_FALSE 12
4 LOAD_FAST 0 (n)
6 LOAD_FAST 1 (d)
8 BINARY_TRUE_DIVIDE
10 JUMP_IF_TRUE_OR_POP 14
>> 12 LOAD_CONST 1 (0)
>> 14 RETURN_VALUE
And it appears that logic_div should actually have an extra step. Up to ‘8’ the two bytecodes are identical. At ’10’ conditional_div would just return a value whereas logic_div has to do a jump if its true and then return. Perhaps the alternative ..._OR_POP is faster than returning so some percent of the time it has a shorter last step? But the only way that ..._OR_POP would be activated is if the numerator were zero and the denominator non-zero. Both bytecodes take the same route when the denominator is zero. This doesn’t feel like a satisfying conclusion. Maybe someone can explain if I’m misunderstanding something.
For reference
>>> sys.version '3.9.6 (tags/v3.9.6:db3ff76, Jun 28 2021, 15:26:21) [MSC v.1929 64 bit (AMD64)]'
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0