number of returns in a function - python

Is there any harm if we use many return positions in a python function ?
Like suppose if I want to return a function if value is not 3 and value is not None (Just a scenario). So it can be done in so many ways like
def return_value(value):
if value != 3:
return None
if value is not None:
return None
if value != 'string':
return None
or It can be done like this:
def return_value(value):
if value != 3 or value is not None or value !='string':
return None
Again, I would like to use second way of writing code only, but just for a doubt I am asking having many returns somehow affects the performance of function or not ?

No, there is no harm in having many returns.
That said, I would in this case definitely go with the second version. The first is harder to read, and slower (although optimizing for speed without a benchmark is always premature). It is not the many returns that make its lower though, but the many ifs.

It seems a very interesting scenario that you have used above, but conceptually there is no issue with multiple return points in a function.
In a real scenario, it is likely that your test conditions will be logically similar, and that grouping them together, as in your second example, will make good logical sense and keep your code easy to read.
Cheers

Related

Use of a temporary variable vs repeatedly read same key/value from a dictionary

Background: I need to read the same key/value from a dictionary (exactly) twice.
Question: There are two ways, as shown below,
Method 1. Read it with the same key twice, e.g.,
sample_map = {'A':1,}
...
if sample_map.get('A', None) is not None:
print("A's value in map is {}".format(sample_map.get('A')))
Method 2. Read it once and store it in a local variable, e.g,
sample_map = {'A':1,}
...
ret_val = sample.get('A', None)
if ret_val is not None:
print("A's value in map is {}".format(ret_val))
Which way is better? What are their Pros and Cons?
Note that I am aware that print() can naturally handle ret_val of None. This is a hypothetical example and I just use it for illustration purposes.
Under these conditions, I wouldn't use either. What you're really interested in is whether A is a valid key, and the KeyError (or lack thereof) raised by __getitem__ will tell you if it is or not.
try:
print("A's value in map is {}".format(sample['A'])
except KeyError:
pass
Or course, some would say there is too much code in the try block, in which case method 2 would be preferable.
try:
ret_val = sample['A']
except KeyError:
pass
else:
print("A's value in map is {}".format(ret_val))
or the code you already have:
ret_val = sample.get('A') # None is the default value for the second argument
if ret_val is not None:
print("A's value in map is {}".format(ret_val))
There isn't any effective difference between the options you posted.
Python: List vs Dict for look up table
Lookups in a dict are about o(1). Same goes for a variable you have stored.
Efficiency is about the same. In this case, I would skip defining the extra variable, since not much else is going on.
But in a case like below, where there's a lot of dict lookups going on, I have plans to refactor the code to make things more intelligible, as all of the lookups clutter or obfuscate the logic:
# At this point, assuming that these are floats is OK, since no thresholds had text values
if vname in paramRanges:
"""
Making sure the variable is one that we have a threshold for
"""
# We might care about it
# Don't check the equal case, because that won't matter
if float(tblChanges[vname][0]) < float(tblChanges[vname][1]):
# Check lower tolerance
# Distinction is important because tolerances are not always the same +/-
if abs(float(tblChanges[vname][0]) - float(tblChanges[vname][1])) >= float(
paramRanges[vname][2]):
# Difference from default is greater than tolerance
# vname : current value, default value, negative tolerance, tolerance units, change date
alerts[vname] = (
float(tblChanges[vname][0]), float(tblChanges[vname][1]), float(paramRanges[vname][2]),
paramRanges[vname][0], tblChanges[vname][2]
)
if abs(float(tblChanges[vname][0]) - float(tblChanges[vname][1])) >= float(
paramRanges[vname][1]):
alerts[vname] = (
float(tblChanges[vname][0]), float(tblChanges[vname][1]), float(paramRanges[vname][1]),
paramRanges[vname][0], tblChanges[vname][2]
)
In most cases—if you can't just rewrite your code to use EAFP as chepner suggests, which you probably can for this example—you want to avoid repeated method calls.
The only real benefit of repeating the get is saving an assignment statement.
If your code isn't crammed in the middle of a complex expression, that just means saving one line of vertical space—which isn't nothing, but isn't a huge deal.
If your code is crammed in the middle of a complex expression, pulling the get out may force you to rewrite things a bit. You may have to, e.g., turn a lambda into a def, or turn a while loop with a simple condition into a while True: with an if …: break. Usually that's a sign that you, e.g., really wanted a def in the first place, but "usually" isn't "always". So, this is where you might want to violate the rule of thumb—but see the section at the bottom first.
On the other side…
For dict.get, the performance cost of repeating the method is pretty tiny, and unlikely to impact your code. But what if you change the code to take an arbitrary mapping object from the caller, and someone passes you, say, a proxy that does a get by making a database query or an RPC to a remote server?
For single-threaded code, calling dict.get with the same arguments twice in a row without doing anything in between is correct. But what if you're taking a dict passed by the caller, and the caller has a background thread also modifying the same dict? Then your code is only correct if you put a Lock or other synchronization around the two accesses.
Or, what if your expression was something that might mutate some state, or do something dangerous?
Even if nothing like this is ever going to be an issue in your code, unless that fact is blindingly obvious to anyone reading your code, they're still going to have to think about the possibility of performance costs and ToCToU races and so on.
And, of course, it makes at least two of your lines longer. Assuming you're trying to write readable code that sticks to 72 or 79 or 99 columns, horizontal space is a scarce resource, while vertical space is much less of a big deal. I think your second version is easier to scan than your first, even without all of these other considerations, but imagine making the expression, say, 20 characters longer.
In the rare cases where pulling the repeated value out of an expression would be a problem, you still often want to assign it to a temporary.
Unfortunately, up to Python 3.7, you usually can't. It's either clumsy (e.g., requiring an extra nested comprehension or lambda just to give you an opportunity to bind a variable) or impossible.
But in Python 3.8, PEP 572 assignment expressions handle this case.
if (sample := sample_map.get('A', None)) is not None:
print("A's value in map is {}".format(sample))
I don't think this is a great use of an assignment expression (see the PEP for some better examples), especially since I'd probably write this the way chepner suggested… but it does show how to get the best of both worlds (assigning a temporary, and being embeddable in an expression) when you really need to.

else vs return to use in a function to prematurely stop processing

[Edit] changed return 0 to return. Side effects of beinga Python n00b. :)
I'm defining a function, where i'm doing some 20 lines of processing. Before processing, i need to check if a certain condition is met. If so, then I should bypass all processing. I have defined the function this way.
def test_funciton(self,inputs):
if inputs == 0:
<Display Message box>
return
<20 line logic here>
Note that the 20 line logic does not return any value, and i'm not using the 0 returned in the first 'if'.
I want to know if this is better than using the below type of code (in terms of performance, or readability, or for any other matter), because the above method looks good to me as it is one indentation less:
def test_function(self,inputs):
if inputs == 0:
<Display Message box>
else:
<20 line logic here>
In general, it improves code readability to handle failure conditions as early as possible. Then the meat of your code doesn't have to worry about these, and the reader of your code doesn't have to consider them any more. In many cases you'd be raising exceptions, but if you really want to do nothing, I don't see that as a major problem even if you generally hew to the "single exit point" style.
But why return 0 instead of just return, since you're not using the value?
First, you can use return without anything after, you don't have to force a return 0.
For the performance way, this question seems to prove you won't notice any difference (except if you're realy unlucky ;) )
In this context, I think it's important to know why inputs can't be zero? Typically, I think the way most programs will handle this is to raise an exception if a bad value is passed. Then the exception can be handled (or not) in the calling routine.
You'll often see it written "Better to ask forgiveness" as opposed to "Look before you leap". Of course, If you're often passing 0 into the function, then the try / except clause could get expensive (try is cheap, except is not).
If you're set on "looking before you leap", I would probably use the first form to keep indentation down.
I doubt the performance is going to be significantly different in either case. Like you I would tend to lean more toward the first method for readability.
In addition to the smaller indentation(which doesn't really matter much IMO), it precludes the necessity to read further for when your inputs == 0:
In the second method one might assume that there is additional processing after the if/else statement, whereas the first one makes it obvious that the method is complete upon that condition.
It really just comes down to personal preference though, you will see both methods used in practice.
Your second example will return after it displays the message box in this case.
I prefer to "return early" as in my opinion it leads to better readability. But then again, most of my returns that happen prior to the actual end of the function tend to be more around short circuiting application logic if certain conditions are not met.

Using dictionaries as switch statements in Python 2.7.3

I like using dictionaries as a form of switch statment, by settings booleans as keys. Example:
>>> def f(a):
... return {True: -a, a==0: 0, a > 0: a}[True]
...
>>> f(-3)
3
>>> f(3)
3
>>> f(0)
0
The key True works as an else/default case and is only returned if no other key is evaluated to True. I am guessing this assumes some sort of order of evaluation for iterating the dictionary.
Now look at the following extract from the latest release announcement from the Python team for the newest versions of branches 2.6, 2.7, 3.1 and 3.2:
Hash randomization causes the iteration order of dicts and sets to be
unpredictable and differ across Python runs. Python has never
guaranteed iteration order of keys in a dict or set, and applications
are advised to never rely on it. Historically, dict iteration order
has not changed very often across releases and has always remained
consistent between successive executions of Python. Thus, some
existing applications may be relying on dict or set ordering.
Does this mean that using dicts as switch calls will not be possible anymore? Or maybe I should use any other class (like OrderedDict or something)? Or maybe I'm completely off and it should not affect this at all?
You misunderstood how this code works.
Your dictionary has only two keys: True and False. There could be multiple conflicting values for the True key but that gets resolved at the initialization of the dictionary.
There's no iteration for a dictionary lookup.
Hash randomization will not affect your application. It should only affect applications that rely on the iteration order of keys in the dictionary.
That said, I find your technique both more obscure than the simple if..elif chain and also less efficient (building a new dict is not cheap).
The way you are using the dictionary to hash the condition would not be affected by the ordering. You are strictly using keys to access the dictionary and the ordering is not important to you as you are not iterating over the keys/values. So your particular usage of dictionary is immune to Python's dictionary hash randomization.
This will probably still work, on the assumption that the dictionary is built in left-to-right order. The points about unordered iteration are about traversal once the dictionary is built, not the construction process itself, and in any event, you are indexing into it, not iterating over it.
But frankly it's not a good idea to rely on this behaviour. It's fragile, as it relies on assumed behaviour (though perhaps there's something in the spec that guarantees this) and is highly confusing, in no small part because the order of evaluation of cases is effectively right-to-left (i.e., the right-most true case wins). A much more comprehensible solution is as follows:
return ( a if a > 0 else
0 if a == 0 else
-a)
First, realize that your code is more or less equivalent to:
def f(a):
d = {}
d[True] = -a
d[a==0] = 0
d[a>0] = a
return d[True]
With that in mind, answer to your question becomes obvious.
Why do you bother with this obscure syntax instead of something simpler?
Even this one is more readable:
def f(a):
return a if a > 0 else 0 if a == 0 else -a
The fact that you seem to misunderstand what your code is really doing should be a clear sign that you're doing something wrong.
This is a very dirty code, the line with the dictionary takes minutes to read (although I work with Python for 3 years), and this will be very hard to debug. The next developer (read: yourself in half a year) will not be able to read this.
switch construct can be replaced with a dict of callbacks, if you need them:
{value1: one_func, value2: another_func, value3: third_func}
If you need only True/False, you don't need any structure:
return one_func() if check else another_func()
In many cases, switch can be replaced with a chain of if ... return:
if check:
return one_func()
return another_func() if another_check else third_func()
All these are much more readable and debuggable.
You are not using iteration in your example, so your code is safe.
However, your solution is a little strange, boolean as a key is not very readable.
Why don't you try:
switch = {
choice1: func1
choice1: func2
...
}
and:
switch[variable]()
That will only affect you if you're doing things like:
mydict.values()[0]
And relying on this to always be the same value. The docs you quote say that that isn't guaranteed to happen.
However, your code has one issue that you need to consider, and that is related to short-circuiting. If you do:
if a == 0:
return 0
elif a > 0:
return a
else:
return -a
Or, more succinctly (but arguably less readably) return 0 if a == 0 else a if a > 0 else -a , and a is 0, then a > 0 is never evaluated (and still won't be even if you don't return above it). Your dictionary needs to evaluate every key you give it as a condition every time. The only reason to try dictionary dispatch instead of chained ifs is efficiency, but in the case where the keys aren't constant and the entire dict precomputable, you can lose out badly.

Check if one of variables is set to None

I recently had to implement a small check for any variables that might have not been initialized (and their default value is None). I came up with this:
if None in (var1, var2, var3):
error_out()
While, in my eyes, bordering on beautiful, I was wondering - is this a good way to do it? Is this the way to do it? Are there any cases in which this would produce some unexpected results?
First things first: your code is valid, readable, concise... so it might not be the way to do it (idioms evolves with time and new language features) but it certainly is one of the way to do it in a pythonic way.
Secondly, just two observations:
The standard way to generate errors in python is to raise Exceptions. You can of course wrap your exception-raising within a function, but since it's quite unusual I was just wondering if you chose this design for some specific reason. Since you can write your own Exception class, even boilerplate code like logging an error message to file could go within the class itself rather than in the wrapping function.
The way you wrote your test is such that you won't be able to assign None as a value to your variables. This might be not a problem now, but might limit your flexibility in the future. An alternative way to check for initialisation could be to simply not declare an initial value for the variable in question and then do something along the lines of:
try:
self.variable_name
except NameError:
# here the code that runs if the variable hasn't been initialised
finally:
# [optional] here the code that should run in either case
A just slightly different way to do it would be to use the built-in all method; however, this will also catch false-ish values like 0 or "", which may not be what you want:
>>> all([1, 2, 3])
True
>>> all([None, 1, 2])
False
>>> all([0, 1])
False
Allow me to leave my two cents here:
>>> any(a is None for a in [1,0])
False
>>> any(a is None for a in [1,0, None])
True
So one can:
def checkNone(*args):
if any(arg is None for arg in args):
error_out()
Nothing new here. Just IMHO maybe the part any arg is None is more readable

In Python, is there a clean way to return the value of a function if it's not None?

I find myself writing a lot of code that resembles the following:
ans = call_function()
if ans:
return ans
...
Is there a clean way to make this a 1 or 2 liner? An "example" of such a paradigm might be
if x as call_function():
return x
It seems that as long as ans is not None, you can just return it, based on your implied usage.
if ans is not None:
return ans
I'm not sure what you're doing after your if, but perhaps you're doing the following:
ans = call_function()
if ans:
return ans
else:
return default
In which case it you can simply do:
return call_function() or default
It may make sense to refactor the code which would follow your if statement into another function. There is a (not unwise) school of thought which emphasizes making each function do one very specific thing.
In this case, you could write something like this:
ans = call_function()
return ans if ans is not None else following_code()
or, if you are really testing for a truthy value (rather than specifically testing for not None):
return call_function() or following_code()
In the not None case, you can still avoid assigning to the temp variable ans by writing a function like this:
def fallback(test_value, routine, *args, **kwargs):
return test_value if test_value is not None else routine(*args, **kwargs)
and then using it like this:
return fallback(call_function(), following_code,
arg_to_following_code, following_code_kwarg=keywordarg_value)
This might be useful if you're doing this sort of thing very frequently, but in general it will just make your code a bit harder to read, because people will not be familiar with your fallback function. The original form used in your question is bulky, but it has a readily recognizable shape that people will be used to seeing. It also does things in a very measured fashion, one logical action per line, as is the norm in Python.
On the other hand, it can be good to cut out extraneous local variables, since these can lead to bugs due to typos or confusion about scope.
Wanting to embed assignments in if statements is probably one of the more common feature requests we see for Python. The problem is that such embedded assignment proposals typically only work for the very limited cases where the value you want to store and the condition you want to check are identical (e.g. your example falls into that trap and would be useless if you instead needed to check a more specific condition like if ans is not None:).
If the extra line really offends you, you can collapse the if statement to a one-liner (if ans: return ans). A lot of people hate that style, though.
However, I question your basic premise that "I want to know if this function returns something meaningful, and if it is, then that is the result of this function as well, otherwise I will fall back and calculate my result some other way" isn't sufficient justification for using a properly scoped local variable.
Knowing whether or not another function has finished the job for you sounds pretty damn important to me.

Categories

Resources