(Python) How to stop calculation after a ZeroDivisionError - python-2.7

Is there a way to stop everything after an exception?
For example, I'm creating a reverse polish notation calculator (to learn postfix) and I want to make sure "Cannot divide by zero" is printed out if there is a "0" in my string.
I got it to do what I wanted using try/except.
I tried putting in a "break" after my print statement in the exception but that obviously does not help because my final "pop" is outside the loop. And that causes a bunch of traceback error as obviously the "divide by zero" operation was not performed and the list becomes messed up.
Any ideas?
def RPN(ll):
mys = Stack()
for x in ll:
if x == '+':
sum_of_two = mys.new_pop() + mys.new_pop()
mys.push(sum_of_two)
"""mys.print_stack()""" #test addition
elif x == "*":
product = mys.new_pop() * mys.new_pop()
mys.push(product)
"""mys.print_stack()""" #test multiplication
elif x == "-":
subtrahend = mys.new_pop()
minuend = mys.new_pop()
subtrahend
minuend
difference = minuend - subtrahend
mys.push(difference)
"""mys.print_stack()""" #test subtraction
elif x == "/":
divisor = mys.new_pop()
dividend = mys.new_pop()
divisor
dividend
try:
quotient = dividend/divisor
mys.push (quotient)
except ZeroDivisionError:
print "Cannot divide by zero"
"""mys.print_stack()""" #test division
else:
mys.push(int(x))
return mys.new_pop()
example = [3,4,"-",5,"+",6,"*",0,"/"] #test reverse polish calc
print RPN(example)

You can return a value from anywhere in a function, not just at the end
try:
quotient = dividend/divisor
mys.push(quotient)
except ZeroDivisionError:
print 'Something to console'
return None
Of course, whatever called this function is going to have to accept None as a valid return value.
Alternatively, if this is a function way down in the control chain, and you want to just bubble all the way up to the top function, just re-raise the error, or raise a different error and catch it at the very top function.
class MyError(Exception):
pass
def func():
try:
func2()
except MyError as e:
print e.message
def func2():
func3():
def func3():
RPN([...])
def RPN(ll):
...
try:
...
except ZeroDivisionError:
raise MyError('Zero Division')

Related

Programm tries to append list with a string although it's not allowed

Hello i am pretty new to python and i am currently writing this program, where i try to find the min and max in a list that is created through inputing numbers sequentialy. When i give the programm the input: 5, a, 1 it gives me the following Error:
Traceback (most recent call last):
File "/home/juli/PycharmProjects/pythonProject/main.py", line 27, in <module>
mx = max(list,key=float)
ValueError: could not convert string to float: 'a'
Code:
def check_for_float(p_input):
try:
ipt = float(p_input)
return ipt
except (ValueError, TypeError):
print("Error, not a numeric input")
return False
list = []
while True:
ipt = input("Please enter a numeric value: ")
if ipt == "done":
break
check_for_float(ipt)
if ipt == type(float) or type(int):
list.append(ipt)
elif ipt == type(str):
continue
if list == []:
quit()
mx = max(list,key=float)
mn = min(list,key=float)
print(f"Maximum = {mx}; Minimum = {mn}")
I don't know why he has trouble converting the str into a float, because normally there shouldn't even be a str in the max() function. My goal is, that the programm leaves str out that's why i put the continue function there. Thanks for any help.
Just remove this part of your code
if ipt == type(float) or type(int):
list.append(ipt)
elif ipt == type(str):
continue
and add this code instead
check = check_for_float(ipt)
if check:
list.append(ipt)
else:
continue
This code will now filter out any character input and only append the valid numeric values into the list.
The complete code should look like this
def check_for_float(p_input):
try:
ipt = float(p_input)
return ipt
except (ValueError, TypeError):
print("Error, not a numeric input")
return False
list = []
while True:
ipt = input("Please enter a numeric value: ")
if ipt == "done":
break
check = check_for_float(ipt)
if check:
list.append(ipt)
else:
continue
if list == []:
quit()
mx = max(list,key=float)
mn = min(list,key=float)
print(f"Maximum = {mx}; Minimum = {mn}")

Breaking out of finally statement without interfering with return value in try statement

Alright, so i have a situation where there is a sequence which has to be executed in particular order inside try statement, if any of the steps fails, return value has to be returned. Also there is a finally statement where i perform some kind of 'go-back-to-safe-state-if-anything-fails' sequence which also has to be executed in particular order. For each step (both try and finally statement), if it fails, some kind of message has to be logged with reason why it failed and execution has to be stopped at this point. Return value of sequence inside finally statement doesn't matter to me (I'm only interested in return value of try statement). This is the way that i decided to deal with it:
def whatever():
ret_val = True
try:
x = foo()
if isinstance(x, str):
print "%s" % x
ret_val = False
return
y = bar()
if isinstance(y, str):
print "%s" % y
ret_val = False
return
finally:
a = safe_state_step_1()
if isinstance(a, str):
print "%s" % a
return ret_val
b = safe_state_step_2()
if isinstance(b, str):
print "%s" % b
return ret_val
return ret_val
What I want to find out if there is a more 'pythonic'/'smarter' way of dealing with this kind of situation?

object returning memory location instead of value

So I have this class:
#!/usr/bin/python3
class MyClass(object):
def __init__(self, length):
self._list = length
def get(self, index):
try:
return self._list[index]
except IndexError:
return None
which takes in a list and returns a value, a list index I think. I am trying to get that value:
def my_function(a_list):
a_list = MyClass
for x in (10**p for p in range(1, 9)):
if a_list:
print(a_list)
def main():
length = my_function(MyClass([i for i in range(0, 543)]))
but I keep getting only the memory location of the list, I think this is supposed to return an int.
I am hoping this is a workable bit of code, but I am struggling, with the concept of passing an "object" to a class, it doesn't make any sense to me.
Here is a test I am supposed to use:
def test_large_list():
s_list = My_Class([i for i in xrange(0, 100000)])
assert len(s_list._list) == list_length(s_list)
Ok, Here is my full function that works, it is done, how od I do this so that the first line takes an argument
#!/usr/bin/python3
#def list_length(single_method_list): This is what I am supposed to work with
from single_method_list import SingleMethodList
def my_function(): # This is how I have done it and it works.
a_list = MyClass([i for i in range(0, 234589)])
for x in (10**p for p in range(1, 8)):
if a_list.get(x):
print("More than", x)
first = x
else:
print("Less than", x)
last = x
break
answer = False
while not answer:
result = (first + last)/2
result = int(round(result))
print(result)
if s_list.get(result):
first = result
print('first', result)
else:
last = result
print('last', result)
if s_list.get(result) and not s_list.get(result + 1):
answer = True
print(result + 1)
my_function()
I don't know what more I can give to explain where I am stuck, it is the OOP part of this that I don't know I need the same results here, just passing it to the function instead of creating it inside the function which I did in order to do the algorithm.
Well your class does something else.MyClass is designed to take a List at initialization, so the naming length is not a good idea.
The get() method of this class takes in a number and returns the element located at that particular index in the initialized self._list.
Your logic should be like:
def my_function(a_list):
a_list = MyClass(a_list)
...
def main():
length = my_function([i for i in range(0, 543)])
Just to clarify some misunderstanding that you might have.
Class does not return anything. It is a blueprint for creating objects.
What can return value is a method (function). For instance, if you want to write a method which returns length of some list:
def my_function(some_list):
return len(some_list)
Or in your case:
def my_function(a_list):
return len(a_list._list)
Note that you should not call your variables list. It's a built-in function in python which creates lists.
And as you can see there is another built-in function len in python which returns length of list, tuple, dictionary etc.
Hope this helps, although it's still a bit unclear what you're trying to achieve.

Recursive function without return - Python 2.7

Can this be called a recursive function ? It does reduce in one way but not in a (amount - 1) type of way...
EDIT:
Also how is it possible to write a recursive function without using return?
def wow(amount):
if amount <= 0:
print "Don't be so negative!"
elif amount == 1:
return "Wow!"
else:
return amount * "Wow! \n"
amount = int(raw_input("How many 'Wow!' do you wanna see : "))
print wow(amount)
No, this is not a recursive function. A recursive function has to call itself. This page explains and shows examples of recursive functions.
This would be a recursive function.
def wow(amount):
if amount <= 0:
return
else:
print("Wow! \n")
return wow(amount - 1)
And a full-fledged solution that turns your code into a recursive function would be.
def wow(amount):
if amount <= 0:
return "Don't be so negative!"
elif amount == 1:
return "Wow!"
else:
return inner_wow("", amount)
def inner_wow(wow_str, amount):
if amount == 0:
return
else:
wow_str += "Wow! \n"
return wow(wow_str, amount - 1)
In response to your second question. All functions have to return something. Even if you don't tell them to return something they still returns None.

python 2.7 - is there a more succint way to do this series of yield statements (in python 3, "yield from" would help)

Situation:
Python 2.7 code that contains a number of "yield" statements. But the specs have changed.
Each yield calls a function that used to always return a value. Now the result is sometimes a value that should be yielded, but sometimes no value should be yielded.
Dumb Example:
BEFORE:
def always(x):
return 11 * x
def do_stuff():
# ... other code; each yield is buried inside an if or other flow construct ...
# ...
yield always(1)
# ...
yield always(6)
# ...
yield always(5)
print( list( do_stuff() ) )
=>
[11, 66, 55]
AFTER (if I could use Python 3, but that is not currently an option):
def maybe(x):
""" only keep odd value; returns list with 0 or 1 elements. """
result = 11 * x
return [result] if bool(result & 1) else []
def do_stuff():
# ...
yield from maybe(1)
# ...
yield from maybe(6)
# ...
yield from maybe(5)
=>
[11, 55]
AFTER (in Python 2.7):
def maybe(x):
""" only keep odd value; returns list with 0 or 1 elements. """
result = 11 * x
return [result] if bool(result & 1) else []
def do_stuff():
# ...
for x in maybe(1): yield x
# ...
for x in maybe(6): yield x
# ...
for x in maybe(5): yield x
NOTE: In the actual code I am translating, the "yields" are buried inside various flow-control constructs. And the "maybe" function has two parameters, and is more complex.
MY QUESTION:
Observe that each call to "maybe" returns either 1 value to yield, or 0 values to yield.
(It would be fine to change "maybe" to return the value, or to return None when there is no value, if that helps.)
Given this 0/1 situation, is there any more succinct way to code?
If as you say you can get away with returning None, then I'd leave the code as it was in the first place:
def maybe(x):
""" only keep odd value; returns either element or None """
result = 11 * x
if result & 1: return result
def do_stuff():
yield maybe(1)
yield maybe(6)
yield maybe(5)
but use a wrapped version instead which tosses the Nones, like:
def do_stuff_use():
return (x for x in do_stuff() if x is not None)
You could even wrap the whole thing up in a decorator, if you wanted:
import functools
def yield_not_None(f):
#functools.wraps(f)
def wrapper(*args, **kwargs):
return (x for x in f(*args, **kwargs) if x is not None)
return wrapper
#yield_not_None
def do_stuff():
yield maybe(1)
yield maybe(6)
yield maybe(5)
after which
>>> list(do_stuff())
[11, 55]