I am trying to use if-else expression which is supposed to break the loop if the if condition fails, but getting an invalid syntax error.
Sample code:
a = 5
while True:
print(a) if a > 0 else break
a-=1
Of course, if I write in the traditional way (not using the one liner) it works.
What is wrong in using the break command after the else keyword?
If I run this, I get the following error:
... print(a) if a > 0 else break
File "<stdin>", line 2
print(a) if a > 0 else break
^
SyntaxError: invalid syntax
This is because
print(a) if a > 5 else break
is a ternary operator. Ternary operators are no if statements. These work with syntax:
<expr1> if <expr2> else <expr3>
It is equivalent to a "virtual function":
def f():
if <expr2>:
return <expr1>
else:
return <expr3>
So that means the part next to the else should be an expression. break is not an expression, it is a statement. So Python does not expect that. You can not return a break.
In python-2.x, print was not a function either. So this would error with the print statement. In python-2.x print was a keyword.
You can rewrite your code to:
a = 5
while True:
if a > 5:
print(a)
else:
break
a -= 1
You can read more about this in the documentation and PEP-308.
If is an expression, break similar to return is a statement. You can't use two statements in a single sentence (unless you use a semicolon which is ugly). I know it would have been really cool if we can do that, but alas that's the way it is.
To put it in slightly simpler terms, you're misusing the 'one-line if statement' (ternary operator). It always evaluates to an expression (i.e., a value). That is,
<expr1> if <condition> else <expr2>
evaluates to <expr1> if <condition> is True, and to <expr2> if <condition> is False. This resulting value can then be used like any Python value, for example:
y = 0
x = (5 if (y > 0) else 6)
print(x) # 6
Of course, the parentheses are completely unnecessary (even discouraged), but hopefully are useful for understanding the meaning of that line.
Therefore,
print(a) if a > 0 else break
tries to evaluate print(a) (which, by the definition of print() in Python 3, always returns None – perfectly valid, but probably not what you usually want) and then break, which does not evaluate to anything because it is a statement (action), not an expression (value), hence the invalid syntax error.
Hence, if you want to execute one of two statements depending on a condition, you really need the multi-line solution proposed by
Willem Van Onsem. There may be hacky ways to do it in one line, but multiple lines is the usual solution for something like this in Python.
Related
Why only if statement is executed & not else statement if we write an if-else with if having constant value. For example this code in python
x=5
if 5:
print("hello 5")
else:
print("bye")
Also the point to be noted is that in second line even if I replace 5 with 500 or any number, if statement will be only executed.Can anyone please explain.
You have to apply some condition to execute the if-else statement such as (if x==5) or (if x==500). In this case, if the condition is justified then it will follow if statement else it will follow else statement. In your scenario, there is no condition to check with a constant number so it will be automatically converted to true.
Python treats all integers greater than 0 as true. Mostly, you'd use this just as a binary choice, checking if an integer is 1. In this case 5 is being found to be true, which means else is not called, as the if was activated.
if 0:
print("Hello")
will not print hello because 0 is false.
if-else requires a boolean response. Any number(positive/negative) other than 0 implies True.
Try:
if 5:
print("hello 5")
else:
print("bye")
output: hello 5
#
if 0:
print("hello 5")
else:
print("bye")
output: bye
Perhaps an additional reason. It used to be the case that python, like c, had no bool type. So instead of saying
boolean = False # or True
you would say
boolean = 0 # or 1 or any other int
Python later added the bool type with True and False constants, but they are really just wrappers of the ints 1 and 0 (infact bool is a subclass of int). This can be seen by
print(True + True)
print(False * 123)
print(True == 1)
print(False == 0)
Think of if-else as a fork.
You go either this way (statements with the if) or that way (statements with else). The decision which way to turn is done by the condition-expression following the keyword if.
If the condition-expression evaluates to
any non-zero value the if-branch will be taken
zero the else-branch will be taken
def singleNumber(nums):
for num in set(nums):
return num if nums.count(num) != 2 #error occurs here
print(singleNumber([1,1,4,5,5]))
This follows the usual python condition expression format. I don't understand why it's giving me a syntax error here.
The purpose of this function is to find number that doesn't occur twice.
If you're going to actually execute a return, you must return something no matter what.
So you could try:
return num if nums.count(num) != 2 else None
However, that's not going to work in this case since it will return on the first check rather checking all the elements for what you want.
In other words, let's say the first element checked is the first 1 in [1,1,4,5,5]. It will work out that there are two copies of that value in the array and then return None, skipping the rest of the elements.
I'd probably rewrite it as:
if nums.count(num) != 2: return num
which basically does what you need in that, if you don't explicitly return something (i.e., all of the values occur twice), the caller gets None implicitly when the function exits.
If you're the type that dislikes implicit things, you can explicitly add return None at the end of the function, though it's not really necessary.
Because you forgot to write what the result should be if the condition is false.
return num if nums.count(num) != 2 else ...what?
And if you didn't want that then you should write a normal if statement instead.
When you use a ternary conditional operator both if and else part are mandatory.
return num if nums.count(num) != 2 else <missing???>
If I have a function with multiple conditional statements where every branch gets executed returns from the function. Should I use multiple if statements, or if/elif/else? For example, say I have a function:
def example(x):
if x > 0:
return 'positive'
if x < 0:
return 'negative'
return 'zero'
Is it better to write:
def example(x):
if x > 0:
return 'positive'
elif x < 0:
return 'negative'
else:
return 'zero'
Both have the same outcome, but is one more efficient or considered more idiomatic than the other?
Edit:
A couple of people have said that in the first example both if statements are always evaluated, which doesn't seem to be the case to me
for example if I run the code:
l = [1,2,3]
def test(a):
if a > 0:
return a
if a > 2:
l.append(4)
test(5)
l will still equal [1,2,3]
I'll expand out my comment to an answer.
In the case that all cases return, these are indeed equivalent. What becomes important in choosing between them is then what is more readable.
Your latter example uses the elif structure to explicitly state that the cases are mutually exclusive, rather than relying on the fact they are implicitly from the returns. This makes that information more obvious, and therefore the code easier to read, and less prone to errors.
Say, for example, someone decides there is another case:
def example(x):
if x > 0:
return 'positive'
if x == -15:
print("special case!")
if x < 0:
return 'negative'
return 'zero'
Suddenly, there is a potential bug if the user intended that case to be mutually exclusive (obviously, this doesn't make much sense given the example, but potentially could in a more realistic case). This ambiguity is removed if elifs are used and the behaviour is made visible to the person adding code at the level they are likely to be looking at when they add it.
If I were to come across your first code example, I would probably assume that the choice to use ifs rather than elifs implied the cases were not mutually exclusive, and so things like changing the value of x might be used to change which ifs execute (obviously in this case the intention is obvious and mutually exclusive, but again, we are talking about less obvious cases - and consistency is good, so even in a simple example when it is obvious, it's best to stick to one way).
Check this out to understand the difference:
>>> a = 2
>>> if a > 1: a = a+1
...
>>> if a > 2: a = a+1
...
>>> a
4
versus
>>> a = 2
>>> if a > 1: a = a+1
... elif a > 2: a = a+1
...
>>> a
3
The first case is equivalent to two distinct if's with empty else statements (or imagine else: pass); in the second case elif is part of the first if statement.
In some cases, elif is required for correct semantics. This is the case when the conditions are not mutually exclusive:
if x == 0: result = 0
elif y == 0: result = None
else: result = x / y
In some cases it is efficient because the interpreter doesn't need to check all conditions, which is the case in your example. If x is negative then why do you check the positive case? An elif in this case also makes code more readable as it clearly shows only a single branch will be executed.
In general (e.g. your example), you would always use an if..elif ladder to explicitly show the conditions are mutually-exclusive. It prevents ambiguity, bugs etc.
The only reason I can think of that you might ever not use elif and use if instead would be if the actions from the body of the preceding if statement (or previous elif statements) might have changed the condition so as to potentially make it no longer mutually exclusive. So it's no longer really a ladder, just separate concatenated if(..elif..else) blocks. (Leave an empty line between the separate blocks, for good style, and to prevent someone accidentally thinking it should have been elif and 'fixing' it)
Here's a contrived example, just to prove the point:
if total_cost>=10:
if give_shopper_a_random_discount():
print 'You have won a discount'
total_cost -= discount
candidate_prime = True
if total_cost<10:
print 'Spend more than $10 to enter our draw for a random discount'
You can see it's possible to hit both conditions, if the first if-block applies the discount, so then we also execute the second, which prints a message which would be confusing since our original total had been >=10.
An elif here would prevent that scenario.
But there could be other scenarios where we want the second block to run, even for that scenario.
if total_cost<10:
<some other action we should always take regardless of original undiscounted total_cost>
In regards to the edit portion of your question when you said:
"A couple of people have said that in the first example both if statements are always evaluated, which doesn't seem to be the case to me"
And then you provided this example:
l = [1,2,3]
def test(a):
if a > 0:
return a
if a > 2:
l.append(4)
test(5)
Yes indeed the list l will still equal [1,2,3] in this case, ONLY because you're RETURNING the result of running the block, because the return statement leads to exiting the function, which would result in the same thing if you used elif with the return statement.
Now try to use the print statement instead of the return one, you'll see that the 2nd if statement will execute just fine, and that 4 will indeed be appended to the list l using append.
Well.. now what if the first ifstatement changes the value of whatever is being evaluated in the 2nd if statement?
And yes that's another situation. For instance, say you have a variable x and you used if statement to evaluate a block of code that actually changed the x value.
Now, if you use another if statement that evaluates the same variable x will be wrong since you're considering x value to be the same as its initial one, while in fact it was changed after the first if was executed. Therefore your code will be wrong.
It happens pretty often, and sometimes you even want it explicitly to be changed. If that's how you want your code to behave, then yes you should use multiple if's which does the job well. Otherwise stick to elif.
In my example, the 1st if block is executed and changed the value of x, which lead to have the 2nd if evaluates a different x (since its value was changed).
That's where elif comes in handy to prevent such thing from happening, which is the primary benefit of using it.
The other secondary good benefit of using elif instead of multiple if's is to avoid confusion and better code readability.
Consider this For someone looking for a easy way:
>>> a = ['fb.com', 'tw.com', 'cat.com']
>>> for i in a:
... if 'fb' in i:
... pass
... if 'tw' in i:
... pass
... else:
... print(i)
output:
fb.com
cat.com
And
>>> a = ['fb.com', 'tw.com', 'cat.com']
>>> for i in a:
... if 'fb' in i:
... pass
... elif 'tw' in i:
... pass
... else:
... print(i)
Output:
cat.com
'If' checks for the first condition then searches for the elif or else, whereas using elif, after if, it goes on checking for all the elif condition and lastly going to else.
elif is a bit more efficient, and it's quite logical: with ifs the program has to evaluate each logical expression every time. In elifs though, it's not always so. However, in your example, this improvement would be very, very small, probably unnoticeable, as evaluating x > 0 is one of the cheapest operations.
When working with elifs it's also a good idea to think about the best order. Consider this example:
if (x-3)**3+(x+1)**2-6*x+4 > 0:
#do something 1
elif x < 0:
#do something 2
Here the program will have to evaluate the ugly expression every time! However, if we change the order:
if x < 0:
#do something 2
elif (x-3)**3+(x+1)**2-6*x+4 > 0:
#do something 1
Now the program will first check if x < 0 (cheap and simple) and only if it isn't, will it evaluate the more complicated expression (btw, this code doesn't make much sense, it's just a random example)
Also, what perreal said.
I know the conditional expression in Python is X if C else Y, but I got some problems in using it.
I have two codes to be compared.
Code 1:
def fun(p):
if len(p) >= 2:
p[1] = 'Ok'
else:
p.append('Ok')
p = [1]
fun(p)
print p
Output of code 1:
[1, 'Ok']
Code 2:
def fun(p):
(p[1] = 'Ok') if (len(p) >= 2) else p.append('OK')
p = [1]
fun(p)
print p
Output of code 2:
(p[1] = 'Ok') if (len(p) >= 2) else p.append('OK')
^
SyntaxError: invalid syntax
I know in code 1, whose format is "if C : X else: Y", the evaluation order is:
C
X
Y
Code 2 throws a syntax error, the reason may be p[1] doesn't exist. So I guess the format "X if C else Y" is evaluated as follows:
X
C
Y
But that is only my guess. does anyone know the real reason why code 2 is wrong while code 1 is right?
The reason you have a SyntaxError is because Python differentiates between statements and expressions.
Assignments, like
p[1] = 'Ok'
are statements and can't be part of an expression, including the conditional expression. See What is the difference between an expression and a statement in Python? for more info.
Order of evaluation doesn't come into it -- SyntaxErrors happen before any code is evaluated, when its being parsed.
In both if statements and conditional expressions, The order of evaluations is ether
Condition
True Statement
or
Condition
False Statement
So, in
if condition:
true_statement
else:
false_statement
or
true_statement if condition else false_statement
only the true or the fase statement is evaluated, depending on the truthiness of the condition.
As Dan D. points out, you can't have statements in expression contexts.
In the interest of learning -- I do not recommend doing it this way -- I'll show you how you could use the inline X if C else Y to accomplish what you're attempting to do:
def fun(p):
p.__setitem__(1, 'Ok') if len(p) >= 2 else p.append('OK')
As you can see, your fist version is much more readable.
Assignment is no expression (others pointed that out). Hence the syntax error.
Regarding your question concerning evaluation order:
In if-else expressions(!) first the condition operand is evaluated, then either the then-operand (leftmost) or the else-operand (rightmost) is evaluated. The other operand is not evaluated.
In or-expressions the operands are evaluated from leftmost to rightmost (a or b or c or d or ...) but only until one is found whose Boolean value is True. The remaining expressions are not evaluated.
In and-expressions the operands are evaluated from leftmost to rightmost (a and b and c and d and ...) but only until one is found whose Boolean value is False. The remaining expressions are not evaluated.
Inner expressions are evaluated before outer expressions (of course): third(second(first()))
In all other cases (a() + b(), f(g(), h()), a[b[c]] = d() + e) the order is defined as specified. Typically it's left-to-right except for assignment (where it is right before left).
I have tried:
>>> l = [1,2,3]
>>> x = 1
>>> x in l and lambda: print("Foo")
x in l && print "Horray"
^
SyntaxError: invalid syntax
A bit of googling revealed that print is a statement in python2 whereas it's a function in python3. But, I have tried the above snipped in python3 and it throws SyntaxError exception.
Any idea on how can I do it in one line? (Readability or google programming practice is not an issue here)
l = [1, 2, 3]
x = 1
if x in l: print "Foo"
I'm not being a smart ass, this is the way to do it in one line. Or, if you're using Python3:
if x in l: print("Foo")
lambda creates, well a lambda. It needs to be called to execute it. You cannot do this that way, because Python doesn't allow statements in this context, only expressions (including function calls).
To make print a function in Python 2.x, try:
from __future__ import print_function
x in l and print('foo')
Be wary though. If you try:
x in l and print('foo') or print('bar')
it won't work, because print returns None, so the first and expression is False, so both prints will be executed. In Python 3.x you don't need the import.
If you won't have complex short-circuiting (i.e. just one and or or), or you know your functions or expressions won't surprise the short-circuiting logic, there's nothing wrong with the code. Otherwise, try the non-short-circuiting 1-liner:
print('foo') if x in l else print('bar')
This form is recommended only if the probability/expectation of the conditional to be True is vastly higher than being False. Otherwise, plain good-old if-else is the way to go.
Getting rid of the shortcomings of print as a statement in Python2.x using from __future__ import print_function is the first step. Then the following all work:
x in l and (lambda: print("yes"))() # what an overkill!
(x in l or print("no")) and print("yes") # note the order, print returns None
print("yes") if x in l else print("no") # typical A if Cond else Y
print("yes" if x in l else "no") # a more condensed form
For even more fun, if you're into this, you can consider this - prints and returns True or False, depending on the x in l condition (to get the False I used the double not):
def check_and_print(x, l):
return x in l and not print("yes") or not not print("no")
That was ugly. To make the print transparent, you could define 2 other version
of print, which return True or False. This could actually be useful for logging:
def trueprint(*args, **kwargs):
print(*args, **kwargs)
return True
def falseprint(*args, **kwargs):
return not trueprint(*args, **kwargs)
result = x in l and trueprint("yes") or falseprint("no")
If you want to print something different in both true and false cases, use a conditional expression to create the value to print: print ('foo' if x in l else 'bar').
If you just want a function in Python 2 that outputs, you can try sys.stdout.write (after you first import sys of course), but keep in mind that this is nowhere near as flexible; here you're treating the standard output as a file-like object (which it is).
lambda almost certainly buys you nothing here.
Using and-or chaining tricks is incredibly un-Pythonic. The fact that people struggled with these hacks anyway, knowing how awful they were, was exactly why those conditional expressions from point 1 were added to the language. There was a lot of discussion regarding syntax.