Try-Finally: Get current returning value - python

I was looking at this list of python quirks and was amused that this returns False:
def t():
try:
return True
finally:
return False
After seeing this I saw the answers here and here which presented the reason why, and that's that the finally clause will always be executed, no exceptions.
My question is, where is the previous return value stored:
def t():
try:
return True
finally:
...
Why doesn't this return None but instead returns the original True?
And is it possible to access the going to be returned value programatically?
def t():
try:
return True
finally:
...
# if returning != None: return False
I'd like to know if it's possible to do this without using a variable for example:
def t():
retval = None
try:
retval = "Set"
finally:
if retval != None:
return retval
else:
return "Not Set"
and
def t():
retval = None
try:
...
finally:
if retval != None:
return retval
else:
return "Not Set"
return 'Set' and 'Not Set' respectively.

Why doesn't this return None but instead returns the original True?
From the docs:
The finally clause is also executed “on the way out” when any other clause of the try statement is left via a break, continue or return statement.
So this means that if a return statement is present in the finally clause that value will be returned (since the finally block is guaranteed to execute fully, any return statement inside it will be executed as well). Otherwise, if the try/except block was going to return a value, that value is returned.
This means that
def t():
try:
print("Inside try")
return "Return from try"
finally:
print("Inside finally")
return "Return from finally"
Will execute exactly as:
def t():
try:
print("Inside try")
# start of old finally block, executed "on the way out"
print("Inside finally")
return "Return from finally"
# end of old finally block, inserted right before return statement in try
return "Return from try"
finally:
pass
And is it possible to access the going to be returned value programatically?
No, you can't access the value after the return statement in other parts of the code without saving it.

Related

How to include identical if block in multiple functions?

I'm sorry to ask such a basic question, but what's the Pythonic way to include the same if block that can conditionally return in multiple functions? Here's my setup:
def a():
if bool:
return 'yeehaw'
return 'a'
def b():
if bool:
return 'yeehaw'
return 'b'
I'd like to factor the common conditional out of the two functions, but I'm not sure how to do so.
Use a decorator or closure
def my_yeehaw(result):
def yeehaw():
if some_bool:
return 'yeehaw'
return result
return yeehaw
a = my_yeehaw('a')
b = my_yeehaw('b')
You could use a lambda that takes in a. bool and a default value to return if the condition is false:
check = lambda condition, default: 'yeehaw' if condition else default
def a():
return check(condition, 'a')
def b():
return check(condition, 'b')
I am new to python but I think you can use a default argument to send a or b based on what is passed to the function.
def a(x='a'):
if condition: #where condition can be True or False
return 'yeehaw'
return x
(note: my naming wasn't the best, consider that same_bool function might be better called identical_if_block(...) to follow your example
And I am also assuming bool_ is a parameter, though it could work as a global. But not as bool which, like any function object, is always Truthy
>>> bool(bool)
True
)
Use a function, as long as it doesn't need to return falsies.
def same_bool(bool_):
" works for any result except a Falsy"
return "yeehaw" if bool_ else None
def a(bool_):
res = same_bool(bool_)
if res:
return res
return 'a'
def b(bool_, same_bool_func):
#you can pass in your boolean chunk function
res = same_bool_func(bool_)
if res:
return res
return 'b'
print ("a(True):", a(True))
print ("a(False):", a(False))
print ("b(True, same_bool):", b(True,same_bool))
print ("b(False, same_bool):", b(False,same_bool))
output:
a(True): yeehaw
a(False): a
b(True, same_bool): yeehaw
b(False, same_bool): b
If you do need falsies, use a special guard value
def same_bool(bool_):
" works for any result"
return False if bool_ else NotImplemented
def a(bool_):
res = same_bool(bool_)
if res is not NotImplemented:
return res
return 'a'
You could also feed in "a" and "b" since they are constant results, but I assume that's only in your simplified example.
def same_bool(bool_, val):
return "yeehaw" if bool_ else val
def a(bool_):
return same_bool(bool_, "a")
I ended up liking the decorator syntax, as the functions that include the duplicative conditional logic have a good deal else going on in them:
# `function` is the decorated function
# `args` & `kwargs` are the inputs to `function`
def yeehaw(function):
def decorated(*args, **kwargs):
if args[0] == 7: return 99 # boolean check
return function(*args, **kwargs)
return decorated
#yeehaw
def shark(x):
return str(x)
shark(7)

Proper way to handle exception when function returns None

What's the best way to handle a case where a function returns None. For example:
def my_function():
if <some_stuff_works>:
return <stuff>
else:
return None
my_var = my_function()
What I'd like to do is raise an exception if my_var is None and then set to a certain value. So something like:
try:
my_var = my_function()
except ValueIsEmpty:
my_var = "EMPTY"
Does that make sense?
If you can't modify the function, there's no need to come up with a creative exception: just check if it is None and give it an appropriate value.
my_var = my_function()
if my_var is None:
my_var = 'default_value'
Since you're want to use exceptions, try this;
def my_function():
if <some_stuff_works>:
return <stuff>
raise ValueError
try:
my_var = my_function()
except ValueError:
my_var = "EMPTY"
You can do this:
var = my_function() or 'default_value'
But, var will be equal to 'default_value' when my_function returns
None (what you want)
False
0
empty list [] (thanks to #roganjosh)
Up to you to choose what you want. If you don't what this, #brianpck's answer's still the best one.
You also make the function raise an exception instead of returning None.
def my_function():
if <some_stuff_works>:
return <stuff>
else:
raise SomeException # maybe TypeError, whatever
And then call it like this:
try:
result = my_function()
except SomeException:
result = 'EMPTY'
Or even better:
def my_function():
if <some_stuff_works>:
return <stuff>
# no need for the else because return end up the function execution.
# so if it returns <stuff>, it will stop, and not look further
return 'EMPTY'

Adding print statement to ValueError exception

New to Python, so I'm sure this is a noob question, but Googling isn't availing me of a clear answer.
Given the following function which is intended to ensure that the user input is a string, why can't I (or how can I) add a print statement when the exception is triggered? The print statement I've inserted there doesn't work.
def string_checker(action):
try:
check = isinstance(action, basestring)
if check == True:
return True
except ValueError:
print "We need a string here!"
return None
action = "words"
string_checker(action)
This may do what you want:
def string_checker(action):
try:
assert isinstance(action, basestring)
return True
except AssertionError:
print "We need a string here!"
return None
action = "words"
string_checker(action)
string_checker(21)
But you could also return "We need a string here!" instead of printing it, or return False, for consistency.
The problem is that you're never raising a value error if action isn't a string. Try this:
def string_checker(action):
try:
check = isinstance(action, basestring)
if check:
return True
else:
raise ValueError
except ValueError:
print "We need a string here!"
return None
But really, I don't think you need an exception. This should work fine:
def string_checker(action):
try:
check = isinstance(action, basestring)
if check:
return True
else:
print "We need a string here!"
return None
I'm not sure I understand. This appears to print "We need a string here!":
def string_checker(action):
try:
raise ValueError()
check = isinstance(action, basestring)
if check == True:
return True
except ValueError:
print "We need a string here!"
return None
action = "words"
string_checker(action)
raw_input('#')
Note the raise ValueError() in the try. Are you sure an exception is being thrown?

Python - how to handle outcome variables that are conditional set correctly

Consider the following:
def funcA():
some process = dynamicVar
if dynamicVar == 1:
return dynamicVar
else:
print "no dynamicVar"
def main():
outcome = funcA()
If the 'some process' part results in a 1, the var dynamicVar is passed back as outcome to the main func. If dynamicVar is anything but 1, the routine fails as no arguments are being return.
I could wrap the outcome as a list:
def funcA():
outcomeList = []
some process = dynamicVar
if dynamicVar == 1:
outcomeList.append(dynamicVar)
return outcomeList
else:
print "no dynamicVar"
return outcomeList
def main():
outcome = funcA()
if outcome != []:
do something using dynamicVar
else:
do something else!
or maybe as a dictionary item. Each of the 2 solutions I can think of involve another set of processing in the main / requesting func.
Is this the 'correct' way to handle this eventuality? or is there a better way?
What is the proper way of dealing with this. I was particularly thinking about trying to catch try: / except: errors, so in that example the uses are reversed, so something along the lines of:
def funcA():
some process = dynamicVar
if dynamicVar == 1:
return
else:
outcome = "no dynamicVar"
return outcome
def main():
try:
funcA()
except:
outcome = funcA.dynamicVar
In Python, all function that do not return a value will implicitly return None. So you can just check if outcome is not None in main().
I believe when you write a function, it's return value should be clear and expected. You should return what you say you will return. That being said, you can use None as a meaningful return value to indicate that the operation failed or produced no results:
def doSomething():
"""
doSomething will return a string value
If there is no value available, None will be returned
"""
if check_something():
return "a string"
# this is being explicit. If you did not do this,
# None would still be returned. But it is nice
# to be verbose so it reads properly with intent.
return None
Or you can make sure to always return a default of the same type:
def doSomething():
"""
doSomething will return a string value
If there is no value available, and empty string
will be returned
"""
if check_something():
return "a string"
return ""
This handles the case with a bunch of complex conditional tests that eventually just fall through:
def doSomething():
if foo:
if bar:
if biz:
return "value"
return ""

__getattr__ keeps returning None even when I attempt to return values

Try running the following code:
class Test(object):
def func_accepting_args(self,prop,*args):
msg = "%s getter/setter got called with args %s" % (prop,args)
print msg #this is prented
return msg #Why is None returned?
def __getattr__(self,name):
if name.startswith("get_") or name.startswith("set_"):
prop = name[4:]
def return_method(*args):
self.func_accepting_args(prop,*args)
return return_method
else:
raise AttributeError, name
x = Test()
x.get_prop(50) #will return None, why?!, I was hoping it would return msg from func_accepting_args
Anyone with an explanation as to why None is returned?
return_method() doesn't return anything. It should return the result of the wrapped func_accepting_args():
def return_method(*args):
return self.func_accepting_args(prop,*args)
Because return_method() doesn't return a value. It just falls out the bottom, hence you get None.

Categories