I have 4 functions. I want my code to perform the first one AND the second, third, or fourth. I also want at least one (any of them) no matter what unless they all fail.
My initial implementation was:
try:
function1(var)
except:
pass
try:
function2(var) or function3(var) or function4(var)
except:
pass
If function2 doesn't work, it doesn't go to function3, how might this be coded to account for that?
In case the success of failure of a function is determined, whether it raises an exception or not, you could write a helper method, that would try to call a list of functions until a successful one returns.
#!/usr/bin/env python
# coding: utf-8
import sys
def callany(*funs):
"""
Returns the return value of the first successfully called function
otherwise raises an error.
"""
for fun in funs:
try:
return fun()
except Exception as err:
print('call to %s failed' % (fun.__name__), file=sys.stderr)
raise RuntimeError('none of the functions could be called')
if __name__ == '__main__':
def a(): raise NotImplementedError('a')
def b(): raise NotImplementedError('b')
# def c(): raise NotImplementedError('c')
c = lambda: "OK"
x = callany(a, b, c)
print(x)
# call to a failed
# call to b failed
# OK
The toy implementation above could be improved by adding support for function arguments.
Runnable snippet: https://glot.io/snippets/ehqk3alcfv
If the functions indicate success by returning a boolean value, you can use them just as in an ordinary boolean expression.
Related
#!/usr/bin/env python
class Functions() :
def A(self):
print "hey"
self.B()
return 1
def B(self):
print "hello"
exit(0)
func_obj = Functions()
def main() :
A = func_obj.A()
print A
print "awesome"
if __name__ == '__main__' :
main()
Above is my code. What I'm trying to do is that I want to call functionA from the main() function and when functionA executes functionB, I want functionB to raise error and exit back to the main() function without going back to functionA. How can I achieve this? Basically I want the main function to print "awesome" after functionB exits. I'm not sure what is the correct keyword to look it up.
What you're looking for are exceptions - they are actually designed to do just this: break the normal flow of execution and propagate up the call stack until someone take care of them (as a last resort, the runtime will catch them, display the error message and a full traceback, and exit).
There are two parts to the process: first raising the exception, then catching it at the right place. In your example it might look like:
# declare our own exception type so we can catch specifically this one
class MyOwnException(Exception):
pass
def a():
print("in a - before b")
b()
print("in a - after b (shouldn't see this)")
def b():
print("in b, before raise")
raise MyOwnException("hello houston ?")
print("in b, after raise (shouldn't see this)")
if __name__ == "__main__":
print("calling a")
try:
a()
print("after a (shouldn't see this)")
except MyOwnException as e:
print("caugth error {}".format(e))
FWIW, your example using exit() was really close since exit() actually works by raising a SysExit exception. The first and main use case for exception is of course error handling, but it's actually really a way to control the execution flow of your program (as an example the StopIteration exception is used to signal an exhausted iterator).
Hey so after someone pointed out my original answer didnt work i went searching! you can create custom exception classes to achieve what you're looking for!
class HaltException(Exception):
pass
class Functions():
def a(self):
print("hey")
self.b()
return "1"
def b(self):
print("hello")
raise HaltException("This is an exception error.")
def main():
func_obj = Functions()
try:
func_obj.a()
except HaltException as error:
print(error)
print("Awesome")
if __name__ == "__main__":
main()
This would then return the following when run :
hey
hello
This is an exception error.
Awesome
I kindly ask for help in solving the following problem: accessing the stack of methods, with the "function name", "arguments" of the function (values) and the return, which has just been executed.
In short: get the chain of execution of methods, with name, arguments and return.
Is there any way to do this without putting decorators in each method?
I have already tried with the traceback module, but it does not work since it shows only the "back" string of the main method below.
I tried with the StackSummary / FrameSummary, but without success too = (
def func_a(param_a1):
print('Executing function A with: {0}'.format(param_a1))
func_b("a", "b")
return "ok"
def func_b(param_b1, param_b2):
print('Executing function B with: {0}, {1}'.format(param_b1, param_b2))
return None
def func_c():
print('Executing function C without args')
return None
if __name__ == '__main__':
# Call function_a()
func_a("testing params")
# Get here???
# call func_a("testing params")
# -> call func_b("a", "b")
# -> call func_c()
# returning None
# returning None
# returning "ok"
Thank you for your attention
I'm writing a program in Python, and nearly every method im my class is written like this:
def someMethod(self):
try:
#...
except someException:
#in case of exception, do something here
#e.g display a dialog box to inform the user
#that he has done something wrong
As the class grows, it is a little bit annoying to write the same try-except block over and over. Is it possible to create some sort of 'global' exception for the whole class? What's the recommended way in Python to deal with this?
Write one or more exception handler functions that, given a function and the exception raised in it, does what you want to do (e.g. displays an alert). If you need more than one, write them.
def message(func, e):
print "Exception", type(e).__name__, "in", func.__name__
print str(e)
Now write a decorator that applies a given handler to a called function:
import functools
def handle_with(handler, *exceptions):
try:
handler, cleanup = handler
except TypeError:
cleanup = lambda f, e: None
def decorator(func):
#functools.wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except exceptions or Exception as e:
return handler(func, e)
else:
e = None
finally:
cleanup(func, e)
return wrapper
return decorator
This only captures the exceptions you specify. If you don't specify any, Exception is caught. Additionally, the first argument can be a tuple (or other sequence) of two handler functions; the second handler, if given, is called in a finally clause. The value returned from the primary handler is returned as the value of the function call.
Now, given the above, you can write:
#handle_with(message, TypeError, ValueError)
def add(x, y):
return x + y
You could also do this with a context manager:
from contextlib import contextmanager
#contextmanager
def handler(handler, *exceptions):
try:
handler, cleanup = handler
except TypeError:
cleanup = lambda e: None
try:
yield
except exceptions or Exception as e:
handler(e)
else:
e = None
finally:
cleanup(e)
Now you can write:
def message(e):
print "Exception", type(e).__name__
print str(e)
def add(x, y):
with handler(message, TypeError, ValueError):
return x + y
Note that the context manager doesn't know what function it's in (you can find this out, sorta, using inspect, though this is "magic" so I didn't do it) so it gives you a little less useful information. Also, the context manager doesn't give you the opportunity to return anything in your handler.
I can think of two options:
Write a decorator that can wrap each method in the try block.
Write a "dispatcher" method that calls the appropriate method inside a try block, then call that method instead of the individual ones. That is, instead of calling obj.someMethod(), obj.otherMethod, you call obj.dispatch('someMethod') or obj.dispatch('otherMethod'), where dispatch is a wrapper that contains the try block.
Your approach seems like a bit of a strange design, though. It might make more sense to have the dialog-box stuff in some other part of the code, some higher-level event loop that catches errors and displays messages about them.
In my code, I need to be able to open and close a device properly, and therefore see the need to use a context manager. While a context manager is usually defined as a class with __enter__ and __exit__ methods, there also seem to be the possibility to decorate a function for use with the context manager (see a recent post and another nice example here).
In the following (working) code snippet, I have implemented the two possibilities; one just need to swap the commented line with the other one:
import time
import contextlib
def device():
return 42
#contextlib.contextmanager
def wrap():
print("open")
yield device
print("close")
return
class Wrap(object):
def __enter__(self):
print("open")
return device
def __exit__(self, type, value, traceback):
print("close")
#with wrap() as mydevice:
with Wrap() as mydevice:
while True:
time.sleep(1)
print mydevice()
What I try is to run the code and stop it with CTRL-C. When I use the Wrap class in the context manager, the __exit__ method is called as expeced (the text 'close' is printed in the terminal), but when I try the same thing with the wrap function, the text 'close' is not printed to the terminal.
My question: Is there a problem with the code snippet, am I missing something, or why is the line print("close") not called with the decorated function?
The example in the documentation for contextmanager is somewhat misleading. The portion of the function after yield does not really correspond to the __exit__ of the context manager protocol. The key point in the documentation is this:
If an unhandled exception occurs in the block, it is reraised inside the generator at the point where the yield occurred. Thus, you can use a try...except...finally statement to trap the error (if any), or ensure that some cleanup takes place.
So if you want to handle an exception in your contextmanager-decorated function, you need to write your own try that wraps the yield and handle the exceptions yourself, executing cleanup code in a finally (or just block the exception in except and execute your cleanup after the try/except). For example:
#contextlib.contextmanager
def cm():
print "before"
exc = None
try:
yield
except Exception, exc:
print "Exception was caught"
print "after"
if exc is not None:
raise exc
>>> with cm():
... print "Hi!"
before
Hi!
after
>>> with cm():
... print "Hi!"
... 1/0
before
Hi!
Exception was caught
after
This page also shows an instructive example.
I am trying to create generic exception handler - for where I can set an arg to return in case of exception, inspired from this answer.
import contextlib
#contextlib.contextmanager
def handler(default):
try:
yield
except Exception as e:
yield default
def main():
with handler(0):
return 1 / 0
with handler(0):
return 100 / 0
with handler(0):
return 'helllo + 'cheese'
But this results in
RuntimeError: generator didn't stop after throw()
The main conceptual problem is that you try to make the calling function implicitly return a value from within a called function. To give an example, what you are trying to do is coneptually equivalent to this situation:
def f():
# some magic code here
def g():
f()
And now you want the magic code to make g() return some value. This is never going to work.
Context managers are the wrong tool for this purpose. Consider using a decorator instead.