What I found out:
In Dive in to Python I read about the peculiar nature of and and or operators
and how shortcircuit evaluation of boolean operators may be used to express conditionals more succinctly via the and-or trick that works very much like the ternary operator in C.
C:
result = condition ? a : b
Python:
result = condition and a or b
This seems to come in handy since lambda functions are restricted to one-liners in Python, but it uses logical syntax to express control flow.
Since Python 2.5 the inline-if seems to have come to the rescue as a more readable syntax for the and-or trick:
result = a if condition else b
So I guess that this is the pythonic replacement for the less readable and-or-construct.
Even if I want to nest multiple conditions, it still looks quite comprehensive:
result = a if condition1 else b if condition2 else c
But in a world of uncertainity I frequently find myself writing some code like this to access a.b.c :
result = a and hasattr(a, 'b') and hasattr(a.b, 'c') and a.b.c or None
So with the help of inline-if I could probably get rid of some ands and ors, resulting in a quite readable piece of code:
result = a.b.c if hasattr(a, 'b') and hasattr(a.b, 'c') else None
I also discovered a somewhat arcane approach for conditonals in this recipe
result = (a, b)[condition]
but this doesn't short-circuit and will result in all kinds of errors if the result of the condition does not return a boolean, 0 or 1.
What I'd like to know:
Now I wonder if it is considered preferable / more pythonic to use the inline-if as much as possible if downwards compatibility is not a concern, or is all just a matter of taste and how much one feels at home in the world of short-circuit evaluation?
Update
I just realized that inline-if is more than syntactic sugar for the and-or-trick, since it will not fail when a is false in a boolean context. So It's probably more fail-proof.
The pythonic thing to do is recognise when you've stretched your code past what is sensible to cram into a single function and just use an ordinary function. Remember, there is nothing you can do with a lambda that couldn't also be done with a named function.
The breaking point will be different for everyone of course, but if you find yourself writing:
return a.b.c if hasattr(a, 'b') and hasattr(a.b, 'c') else None
too much, consider just doing this instead:
try:
return a.b.c
except AttributeError:
return None
Since there is is a special language construct with the inline if-else that does what you want and which was introduced to replace ugly workarounds like those you mention, it is a good idea to use it. Especially since hacks like the and-or trick usually have unexpected corner cases/bugs.
The and-or trick for example fails in this case:
a = 0
b = 1
c = True and a or b
c will be 1, which is not what you expect if you are looking for if-else semantics.
So why use buggy workarounds when there is a language construct that does exactly what you want?
I would rather be explicit about what my code is doing. Inline if is very explicitly doing conditional assignment and readability does count. Inline if would not have made it into the language if and/or side affects were considered preferable.
The pep for conditional expressions goes in to more detail about why that specific syntax was selected and it specifically discusses the and/or hack:
http://www.python.org/dev/peps/pep-0308/
This is for the particular case you mentioned, but I think that mostly every case in which you need chained short-circuit logic can be handled with a more elegant solution. Which is obviously a matter of taste, let me add, so scratch that if you think the above is better than this:
try:
foo = a.b.c
except AttributeError:
print "woops"
In other, less straightforward cases, encapsulating all the testing in a function might improve readibility a lot.
EDIT: by the way, duck typing.
Related
First, the code:
>>> False or 'hello'
'hello'
This surprising behavior lets you check if x is not None and check the value of x in one line:
>>> x = 10 if randint(0,2) == 1 else None
>>> (x or 0) > 0
# depend on x value...
Explanation: or functions like this:
if x is false, then y, else x
No language that I know lets you do this. So, why does Python?
It sounds like you're combining two issues into one.
First, there's the issue of short-circuiting. Marcin's answer addresses this issue perfectly, so I won't try to do any better.
Second, there's or and and returning the last-evaluated value, rather than converting it to bool. There are arguments to be made both ways, and you can find many languages on either side of the divide.
Returning the last-evaluated value allows the functionCall(x) or defaultValue shortcut, avoids a possibly wasteful conversion (why convert an int 2 into a bool 1 if the only thing you're going to do with it is check whether it's non-zero?), and is generally easier to explain. So, for various combinations of these reasons, languages like C, Lisp, Javascript, Lua, Perl, Ruby, and VB all do things this way, and so does Python.
Always returning a boolean value from an operator helps to catch some errors (especially in languages where the logical operators and the bitwise operators are easy to confuse), and it allows you to design a language where boolean checks are strictly-typed checks for true instead of just checks for nonzero, it makes the type of the operator easier to write out, and it avoids having to deal with conversion for cases where the two operands are different types (see the ?: operator in C-family languages). So, for various combinations of these reasons, languages like C++, Fortran, Smalltalk, and Haskell all do things this way.
In your question (if I understand it correctly), you're using this feature to be able to write something like:
if (x or 0) < 1:
When x could easily be None. This particular use case isn't very useful, both because the more-explicit x if x else 0 (in Python 2.5 and later) is just as easy to write and probably easier to understand (at least Guido thinks so), but also because None < 1 is the same as 0 < 1 anyway (at least in Python 2.x, so you've always got at least one of the two options)… But there are similar examples where it is useful. Compare these two:
return launchMissiles() or -1
return launchMissiles() if launchMissiles() else -1
The second one will waste a lot of missiles blowing up your enemies in Antarctica twice instead of once.
If you're curious why Python does it this way:
Back in the 1.x days, there was no bool type. You've got falsy values like None, 0, [], (), "", etc., and everything else is true, so who needs explicit False and True? Returning 1 from or would have been silly, because 1 is no more true than [1, 2, 3] or "dsfsdf". By the time bool was added (gradually over two 2.x versions, IIRC), the current logic was already solidly embedded in the language, and changing would have broken a lot of code.
So, why didn't they change it in 3.0? Many Python users, including BDFL Guido, would suggest that you shouldn't use or in this case (at the very least because it's a violation of "TOOWTDI"); you should instead store the result of the expression in a variable, e.g.:
missiles = launchMissiles()
return missiles if missiles else -1
And in fact, Guido has stated that he'd like to ban launchMissiles() or -1, and that's part of the reason he eventually accepted the ternary if-else expression that he'd rejected many times before. But many others disagree, and Guido is a benevolent DFL. Also, making or work the way you'd expect everywhere else, while refusing to do what you want (but Guido doesn't want you to want) here, would actually be pretty complicated.
So, Python will probably always be on the same side as C, Perl, and Lisp here, instead of the same side as Java, Smalltalk, and Haskell.
No language that i know lets you do this. So, why Python do?
Then you don't know many languages. I can't think of one language that I do know that does not exhibit this "shortcircuiting" behaviour.
It does it because it is useful to say:
a = b or K
such that a either becomes b, if b is not None (or otherwise falsy), and if not it gets the default value K.
Actually a number of languages do. See Wikipedia about Short-Circuit Evaluation
For the reason why short-circuit evaluation exists, wikipedia writes:
If both expressions used as conditions are simple boolean variables,
it can be actually faster to evaluate both conditions used in boolean
operation at once, as it always requires a single calculation cycle,
as opposed to one or two cycles used in short-circuit evaluation
(depending on the value of the first).
This behavior is not surprising, and it's quite straightforward if you consider Python has the following features regarding or, and and not logical operators:
Short-circuit evaluation: it only evaluates operands up to where it needs to.
Non-coercing result: the result is one of the operands, not coerced to bool.
And, additionally:
The Truth Value of an object is False only for None, False, 0, "", [], {}. Everything else has a truth value of True (this is a simplification; the correct definition is in the official docs)
Combine those features, and it leads to:
or : if the first operand evaluates as True, short-circuit there and return it. Or return the 2nd operand.
and: if the first operand evaluates as False, short-circuit there and return it. Or return the 2nd operand.
It's easier to understand if you generalize to a chain of operations:
>>> a or b or c or d
>>> a and b and c and d
Here is the "rule of thumb" I've memorized to help me easily predict the result:
or : returns the first "truthy" operand it finds, or the last one.
and: returns the first "falsy" operand it finds, or the last one.
As for your question, on why python behaves like that, well... I think because it has some very neat uses, and it's quite intuitive to understand. A common use is a series of fallback choices, the first "found" (ie, non-falsy) is used. Think about this silly example:
drink = getColdBeer() or pickNiceWine() or random.anySoda or "meh, water :/"
Or this real-world scenario:
username = cmdlineargs.username or configFile['username'] or DEFAULT_USERNAME
Which is much more concise and elegant than the alternative.
As many other answers have pointed out, Python is not alone and many other languages have the same behavior, for both short-circuit (I believe most current languanges are) and non-coercion.
"No language that i know lets you do this. So, why Python do?" You seem to assume that all languages should be the same. Wouldn't you expect innovation in programming languages to produce unique features that people value?
You've just pointed out why it's useful, so why wouldn't Python do it? Perhaps you should ask why other languages don't.
You can take advantage of the special features of the Python or operator out of Boolean contexts. The rule of thumb is still that the result of your Boolean expressions is the first true operand or the last in the line.
Notice that the logical operators (or included) are evaluated before the assignment operator =, so you can assign the result of a Boolean expression to a variable in the same way you do with a common expression:
>>> a = 1
>>> b = 2
>>> var1 = a or b
>>> var1
1
>>> a = None
>>> b = 2
>>> var2 = a or b
>>> var2
2
>>> a = []
>>> b = {}
>>> var3 = a or b
>>> var3
{}
Here, the or operator works as expected, returning the first true operand or the last operand if both are evaluated to false.
This is not a duplicate of Assignment inside lambda expression in Python, i.e., I'm not asking how to trick Python into assigning in a lambda expression.
I have some λ-calculus background. Considering the following code, it
looks like Python is quite willing to perform side-effects in lambda
expressions:
#!/usr/bin/python
def applyTo42(f):
return f(42)
def double(x):
return x * 2
class ContainsVal:
def __init__(self, v):
self.v = v
def store(self, v):
self.v = v
def main():
print('== functional, no side effects')
print('-- print the double of 42')
print(applyTo42(double))
print('-- print 1000 more than 42')
print(applyTo42(lambda x: x + 1000))
print('-- print c\'s value instead of 42')
c = ContainsVal(23)
print(applyTo42(lambda x: c.v))
print('== not functional, side effects')
print('-- perform IO on 42')
applyTo42(lambda x: print(x))
print('-- set c\'s value to 42')
print(c.v)
applyTo42(lambda x: c.store(x))
print(c.v)
#print('== illegal, but why?')
#print(applyTo42(lambda x: c.v = 99))
if __name__ == '__main__':
main()
But if I uncomment the lines
print('== illegal, but why?')
print(applyTo42(lambda x: c.v = 99))
I'll get
SyntaxError: lambda cannot contain assignment
Why not? What is the deeper reason behind this?
As the code demonstrates, it cannot be about “purity” in a
functional sense.
The only explanation I can imagine is that assignemts do not
return anything, not even None. But that sounds lame and would
be easy to fix (one way: make lambda expressions return None if
body is a statement).
Not an answer:
Because it's defined that way (I want to know why it's defined that way).
Because it's in the grammar (see above).
Use def if you need statements (I did not ask for how to get
statements into a function).
“This would change syntax / the language / semantics” would be ok as an answer if you can come up with an example of such a change, and why it would be bad.
The entire reason lambda exists is that it's an expression.1 If you want something that's like lambda but is a statement, that's just def.
Python expressions cannot contain statements. This is, in fact, fundamental to the language, and Python gets a lot of mileage out of that decision. It's the reason indentation for flow control works instead of being clunky as in many other attempts (like CoffeeScript). It's the reason you can read off the state changes by skimming the first object in each line. It's even part of the reason the language is easy to parse, both for the compiler and for human readers.2
Changing Python to have some way to "escape" the statement-expression divide, except maybe in a very careful and limited way, would turn it into a completely different language, and one that no longer had many of the benefits that cause people to choose Python in the first place.
Changing Python to make most statements expressions (like, say, Ruby) would again turn it into a completely different language without Python's current benefits.
And if Python did make either of those changes, then there'd no longer be a reason for lambda in the first place;2,3 you could just use def statements inside an expression.
What about changing Python to instead make assignments expressions? Well, it should be obvious that would break "you can read off the state changes by skimming the first object in each line". Although Guido usually focuses on the fact that if spam=eggs is an error more often than a useful thing.
The fact that Python does give you ways to get around that when needed, like setattr or even explicitly calling __setitem__ on globals(), doesn't mean it's something that should have direct syntactic support. Something that's very rarely needed doesn't deserve syntactic sugar—and even more so for something that's unusual enough that it should raise eyebrows and/or red flags when it actually is done.
1. I have no idea whether that was Guido's understanding when he originally added lambda back in Python 1.0. But it's definitely the reason lambda wasn't removed in Python 3.0.
2. In fact, Guido has, multiple times, suggested that allowing an LL(1) parser that humans can run in their heads is sufficient reason for the language being statement-based, to the point that other benefits don't even need to be discussed. I wrote about this a few years ago if anyone's interested.
3. If you're wondering why so many languages do have a lambda expression despite already having def: In many languages, ranging from C++ to Ruby, function aren't first-class objects that can be passed around, so they had to invent a second thing that is first-class but works like a function. In others, from Smalltalk to Java, functions don't even exist, only methods, so again, they had to invent a second thing that's not a method but works like one. Python has neither of those problems.
4. A few languages, like C# and JavaScript, actually had perfectly working inline function definitions, but added some kind of lambda syntax as pure syntactic sugar, to make it more concise and less boilerplatey. That might actually be worth doing in Python (although every attempt at a good syntax so far has fallen flat), but it wouldn't be the current lambda syntax, which is nearly as verbose as def.
There is a syntax problem: an assignment is a statement, and the body of a lambda can only have expressions. Python's syntax is designed this way1. Check it out at https://docs.python.org/3/reference/grammar.html.
There is also a semantics problem: what does each statement return?
I don't think there is interest in changing this, as lambdas are meant for very simple and short code. Moreover, a statement would allow sequences of statements as well, and that's not desirable for lambdas.
It could be also fixed by selectively allowing certain statements in the lambda body, and specifying the semantics (e.g. an assignment returns None, or returns the assigned value; the latter makes more sense to me). But what's the benefit?
Lambdas and functions are interchangeable. If you really have a use-case for a particular statement in the body of a lambda, you can define a function that executes it, and your specific problem is solved.
Perhaps you can create a syntactic macro to allow that with MacroPy3 (I'm just guessing, as I'm a fan of the project, but still I haven't had the time to dive in it).
For example MacroPy would allow you to define a macro that transforms f[_ * _] into lambda a, b: a * b, so it should not be impossible to define the syntax for a lambda that calls a function you defined.
1 A good reason to not change it is that it would cripple the syntax, because a lambda can be in places where expressions can be. And statements should not. But that's a very subjective remark of my own.
My answer is based on chepner's comment above and doesn't draw from any other credible or official source, however I think that it will be useful.
If assignment was allowed in lambda expressions, then the error of confusing == (equality test) with = (assignment) would have more chances of escaping into the wild.
Example:
>>> # Correct use of equality test
... list(filter(lambda x: x==1, [0, 1, 0.0, 1.0, 0+0j, 1+0j]))
[1, 1.0, (1+0j)]
>>> # Suppose that assignment is used by mistake instead of equality testing
... # and the return value of an assignment expression is always None
... list(filter(lambda x: None, [0, 1, 0.0, 1.0, 0+0j, 1+0j]))
[]
>>> # Suppose that assignment is used by mistake instead of equality testing
... # and the return value of an assignment expression is the assigned value
... list(filter(lambda x: 1, [0, 1, 0.0, 1.0, 0+0j, 1+0j]))
[0, 1, 0.0, 1.0, 0j, (1+0j)]
As long as exec() (and eval()) is allowed inside lambda, you can do assignments inside lambda:
q = 3
def assign(var_str, val_str):
exec("global " + var_str + "; " +
var_str + " = " + val_str)
lambda_assign = lambda var_str, val_str: assign(var_str, val_str)
q ## gives: 3
lambda_assign("q", "100")
q ## gives: 100
## what would such expression be a win over the direct:
q = 100
## ? `lambda_assign("q", "100")` will be for sure slower than
## `q = 100` isn't it?
q_assign = lambda v: assign("q", v)
q_assign("33")
q ## 33
## but do I need lambda for q_assign?
def q_assign(v): assign("q", v)
## would do it, too, isn't it?
But since lambda expressions allow only 1 expression to be defined inside their body (at least in Python ...), what would be the point of to allow an assignment inside a lambda? Its net effect would be to assign directly (without using any lambda) q = 100, isn't it?
It would be even faster than doing it over a defined lambda, since you have at least one function lookup and execution less to execute ...
There's not really any deeper reasons, it has nothing to do with lambda or functional language designs, it's just to avoid programmers from mixing = and == operators, which is a very common mistake in other languages
IF there's more to this story, I assume like MAYBE because python bdfl GVR has expressed his unloving sides to lambda and other functional features and attempted(and conceded) to remove them from python 3 altogether https://www.artima.com/weblogs/viewpost.jsp?thread=98196
At the time of this writing the core devs were seen having a heated discussions recently on whether to include a limited name binding expression assignment, the debate is still on going so perhaps someday we may see it in lambda(unlikely)
As you said it yourself it is definitely not about side effects or purity, they just don't want lambda to be more than a single expression... ... ...
With that said, here's something about multi expressions assignments in lambda, read on if you're interested
It is not at all impossible in python, in fact it was sometimes necessary to capture variable and sidestep late bindings by (ab)using kwargs(keyword arguments)
edit:
code example
f = lambda x,a=1: (lambda c = a+2, b = a+1: (lambda e = x,d = c+1: print(a,b,c,d,e))())()
f("w")
# output 1 2 3 4 w
# expression assignment through an object's method call
if let(a=1) .a > 0 and let(b=let.a+1) .b != 1 and let(c=let.b+let.a) .c:
print(let.a, let.b, let.c)
# output 1 2 3
As it stands, Python was designed as a statement-based language. Therefore assignment and other name bindings are statements, and do not have any result.
The Python core developers are currently discussing PEP 572, which would introduce a name-binding expression.
I think all the fellows answered this already. We use mostly lambdas function when we just want to:
-create some simple functions that do the work perfectly in a specific place(most of the time hidden inside some other big functions
-The lambda function does not have a name
-Can be used with some other built-ins functions such as map, list and so forth ...
>>> Celsius = [39.2, 36.5, 37.3, 37.8]
>>> Fahrenheit = map(lambda x: (float(9)/5)*x + 32, Celsius) # mapping the list here
>>> print Fahrenheit
[102.56, 97.700000000000003, 99.140000000000001, 100.03999999999999]
Please visit this webpage , this could be useful.Keep it up !!!
https://www.python-course.eu/lambda.php
I'm trying to write a python function in a functional way. The problem is I don't know, how to transform an if conditional into a functional style. I have two variables: A and C, which I want to check for the following conditions:
def function():
if(A==0): return 0
elif(C!=0): return 0
elif(A > 4): return 0
else: someOtherFunction()
I looked at the lambda shortcircuiting, but I couldn't get it to work.
I thank you in advance for your help!
From the link you posted:
FP either discourages or outright disallows statements,
and instead works with the evaluation of expressions
So instead of if-statements, you could use a conditional expression:
def function():
return (0 if ((A == 0) or (C != 0) or (A > 4)) else
someOtherFunction())
or, (especially useful if there were many different values):
def function():
return (0 if A == 0 else
0 if C != 0 else
0 if A > 4 else
someOtherFunction())
By the way, the linked article proposes
(<cond1> and func1()) or (<cond2> and func2()) or (func3())
as a short-curcuiting equivalent to
if <cond1>: func1()
elif <cond2>: func2()
else: func3()
The problem is they are not equivalent! The boolean expression fails to return the right value when <cond1> is Truish but func1() is Falsish (e.g. False or 0 or None). (Or similarly when <cond2> is Truish but func2 is Falsish.)
(<cond1> and func1())
is written with the intention of evaluating to func1() when <cond1> is Truish, but when func1() is Falsish, (<cond1> and func1()) evaluates to False, so the entire expression is passed over and Python goes on to evaluate (<cond2> and func2()) instead of short-circuiting.
So here is a bit of interesting history. In 2005,
Raymond Hettinger found a similar hard-to-find bug in type(z)==types.ComplexType and z.real or z when z = (0+4j) because z.real is Falsish. Motivated by a desire to save us from similar bugs, the idea of using a less error-prone syntax (conditional expressions) was born.
There's nothing non-"functional style" in your current code! who said conditionals are not functional anyway? Practically all functional languages have a conditional operator of some sort, for instance the cond special form in Lisp.
I'd take issue with the code if it were using the assignment operator, or mutating state in some way (say, appending to a list) but as it is, the function in the question is already in a "functional style" - there are no state changes.
Perhaps you meant something like this?
return A != 0 and C == 0 and A <= 4 and someOtherFunction()
The above will return False if either A == 0 or C != 0 or A > 4, in all other cases it will return the value of calling someOtherFunction(). And by the way, False can be assumed to evaluate to 0 (for example, 42 + False == 42), so the semantics in the code in the question will be preserved from the caller's point of view.
Notice that you're taking the information in the link out of context. There's absolutely no need to use a lambda for this, the article is only explaining how to get around an inherent limitation of lambdas in Python, which is that you can't return statements inside (like if-elif-else) - only expressions are allowed, but you can fake them with boolean operators. In the context of a normal function by all means, use conditionals.
Although Peter Norvig is a really great guy, his website is pretty hard to search.
I remember reading about Can I do the equivalent of (test ? result : alternative) in Python? on his site a while back during some research before a functional Python talk.
I'm not going to sway you one way or the other in light of my findings, but you should still go and read the section about ternary conditional operators in a functional style.
def if_(test, result, alternative=None):
"If test is true, 'do' result, else alternative. 'Do' means call if callable."
if test:
if callable(result): result = result()
return result
else:
if callable(alternative): alternative = alternative()
return alternative
Just use it as you have it.
Python does not have the syntax and library built-ins to make it easy to program all functions to directly return a single expression. That's not the most important part of functional style anyway, the most important part is making sure that your functions maintain referential integrity. Basically this means that whenever you supply them with the same input values they return the same output.
So when trying to program functionally in Python, I do not refrain from using statements entirely. I use a block of local variable assignments as an equivalent of let ... in ... from Haskell. I use an if/elif/else chain as an equivalent of a case expression from Haskell. And often there are built-in types which do not provide an adequate interface to create new "modified" versions of them rather than updating them in-place, so you instead have to implement such operations with an explicit copy operation and then using mutations on the new copy.
Python allows you to implement functional-style designs directly. You can easily structure your program as a whole bunch of functions which explicitly pass state around and don't have side effects, so you can design your high level algorithms in a very similar way that you would in a functional programming language. Nearly every programming language supports functional programming in this sense, if you're prepared to stomach the boilerplate necessary to fake first class functions. Since Python has first class functions, you don't even have to put up with boilerplate.
But that's as far as Python goes in supporting functional programming. It does't really support implementing functions as single referentially-transparent expressions. But that doesn't really matter. In a language that doesn't enforce or track purity, you get pretty much all the benefits of functional programming that you can by simply designing your program as a bunch of referentially transparent functions, and then how you implement those functions doesn't actually matter as long as the interface is kept referentially transparent.
Friday I had a discussion with someone about the following contruction:
class C(....
c = C()
d = C()
...
(c if some_boolean else d).some_function_of_class_C()
Is this kind of if statement acceptable/encouraged?
The problem is that a lot of people I work with have C experience but not that much Python experience and are not used to such statement (same like list comprehension).
However, Python is not C and I think the advantages of the Python language should be used.
Or not?
(btw, I use normal function names and variable names but it is just for the sake of this example to keep it sample. Also I do not only call f() but some more functions (like f().g() which I woud have to repeat completely in that case.
There's nothing technically wrong with your code, but it is a little odd and surprising to see code like that.
Splitting your statement into two separate statements improves the readability:
c = c1 if some_boolean else c2
c.some_function_of_class_C()
The terrible variable names you have chosen still make it look awful. But changing the variable names also helps to improve the readability:
vehicle = plane if distance > 1000 else car
vehicle.travel()
That is a lot more readable than what you originally proposed, in my opinion, and it only took a very small change.
It is syntactically and semantically valid, but it certainly isn't Pythonic. Consider using the Strategy pattern instead.
Writing code in one language but using the styles and limitations of another language are never a good idea in the long run. Your python code should always be pythonic.
That said, make sure your code is readable assuming that the person reading the code understands python syntax, or at least enough to google the rest.
Suppose I have an if statement with a return. From the efficiency perspective, should I use
if(A > B):
return A+1
return A-1
or
if(A > B):
return A+1
else:
return A-1
Should I prefer one or another when using a compiled language (C) or a scripted one (Python)?
Since the return statement terminates the execution of the current function, the two forms are equivalent (although the second one is arguably more readable than the first).
The efficiency of both forms is comparable, the underlying machine code has to perform a jump if the if condition is false anyway.
Note that Python supports a syntax that allows you to use only one return statement in your case:
return A+1 if A > B else A-1
From Chromium's style guide:
Don't use else after return:
# Bad
if (foo)
return 1
else
return 2
# Good
if (foo)
return 1
return 2
return 1 if foo else 2
I personally avoid else blocks when possible. See the Anti-if Campaign
Also, they don't charge 'extra' for the line, you know :p
"Simple is better than complex" & "Readability is king"
delta = 1 if (A > B) else -1
return A + delta
Regarding coding style:
Most coding standards no matter language ban multiple return statements from a single function as bad practice.
(Although personally I would say there are several cases where multiple return statements do make sense: text/data protocol parsers, functions with extensive error handling etc)
The consensus from all those industry coding standards is that the expression should be written as:
int result;
if(A > B)
{
result = A+1;
}
else
{
result = A-1;
}
return result;
Regarding efficiency:
The above example and the two examples in the question are all completely equivalent in terms of efficiency. The machine code in all these cases have to compare A > B, then branch to either the A+1 or the A-1 calculation, then store the result of that in a CPU register or on the stack.
EDIT :
Sources:
MISRA-C:2004 rule 14.7, which in turn cites...:
IEC 61508-3. Part 3, table B.9.
IEC 61508-7. C.2.9.
With any sensible compiler, you should observe no difference; they should be compiled to identical machine code as they're equivalent.
Version A is simpler and that's why I would use it.
And if you turn on all compiler warnings in Java you will get a warning on the second Version because it is unnecesarry and turns up code complexity.
This is a question of style (or preference) since the interpreter does not care. Personally I would try not to make the final statement of a function which returns a value at an indent level other than the function base. The else in example 1 obscures, if only slightly, where the end of the function is.
By preference I use:
return A+1 if (A > B) else A-1
As it obeys both the good convention of having a single return statement as the last statement in the function (as already mentioned) and the good functional programming paradigm of avoiding imperative style intermediate results.
For more complex functions I prefer to break the function into multiple sub-functions to avoid premature returns if possible. Otherwise I revert to using an imperative style variable called rval. I try not to use multiple return statements unless the function is trivial or the return statement before the end is as a result of an error. Returning prematurely highlights the fact that you cannot go on. For complex functions that are designed to branch off into multiple subfunctions I try to code them as case statements (driven by a dict for instance).
Some posters have mentioned speed of operation. Speed of Run-time is secondary for me since if you need speed of execution Python is not the best language to use. I use Python as its the efficiency of coding (i.e. writing error free code) that matters to me.
I know the question is tagged python, but it mentions dynamic languages so thought I should mention that in ruby the if statement actually has a return type so you can do something like
def foo
rv = if (A > B)
A+1
else
A-1
end
return rv
end
Or because it also has implicit return simply
def foo
if (A>B)
A+1
else
A-1
end
end
which gets around the style issue of not having multiple returns quite nicely.
From a performance point of view, it doesn't matter in Python, and I'd assume the same for every modern language out there.
It really comes down to style and readability. Your second option (if-else block) is more readable than the first, and a lot more readable than the one-liner ternary operation.