python newbie here. I wonder if I can write the append and print syntax in a line instead of two. I tried twice but failed, as shown below:
a = [1,2,3,4]
y = 7
a.append(y)
print(a) #correct [1, 2, 3, 4, 7]
(1)
print(a.append(y)) #retuns None
(2)
print(a = a.append(y)) #returns 'a' is an invalid keyword argument for print()
A more important question is: May I know the reason of failure? Thank you for your answer.
.append() returns None, so that's what print() is printing in attempt #1.
In attempt #2, you can't perform an assignment quite like that. If you have Python 3.8 or later, you can use the assignment expression operator := like this:
print(a := a.append(y))
but not only will that still not print a, it replaces a with the None that .append() returns.
As for how to add to a and print a at the same time, since .append() returns None, this construct will work:
print(a.append(y) or a)
Since the left side of the or will evaluate to None, the value of the expression will be the right side, a.
But I wouldn't do that. It's unnecessary and confusing. Clever one-liners are no substitute for readable code.
I think you can't do this using append, but try this:
a = [1,2,3,4]
y = 7
print([*a,y])
Related
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.
I have a small snippet of code with two functions in it.
I want to call the first function if it receives a response then perform a function on that response. Then assign the result to another variable.
In a verbose way it looks like:
result = get_something()
if result:
answer = transform(result)
alternatively I could do
if get_something():
answer = transform(get_something())
but that requires calling the first function twice
is there a way to do all of this on one line a bit like a ternary (maybe as a lambda)
answer = transform(result) if get_something() else None
Obviously in the above there is nothing to state what result is but I need to say basically where result = get_something()
I can do that in a list comprehension but that seems a bit dumb
answer = [transform(x) for x in [get_something()] if x][0]
In the latest Python version (Python 3.8) there's a new assignment that may be useful for you, :=:
There is new syntax := that assigns values to variables as part of a larger expression. It is affectionately known as “walrus operator” due to its resemblance to the eyes and tusks of a walrus.
if (n := len(a)) > 10:
print(f"List is too long ({n} elements, expected <= 10)")
In this example, the assignment expression helps avoid calling len() twice:
We can in Python 3.8 with assignment expressions:
if (result := get_something()) is not None:
# do something with result
Although I don't fully understand the reasons for doing things this way (which is less clear than any of the others), here's an example using lambda:
>>> def get_something(flag): # Added the flag argument, to mimic different return values
... return 5 if flag else None
...
>>> answer = (lambda func, arg: func(arg) if arg else None)(int, get_something(True))
>>> answer
5
>>> answer = (lambda func, arg: func(arg) if arg else None)(int, get_something(False))
>>> answer
>>>
Can someone tell me how exactly Python's for loops are implemented? The reason I'm asking this is because I'm getting different behavior in the following two for loops when I expect the same behavior (assuming cases is just a set of elements):
First for loop:
for case in cases:
blah
Second for loop:
for i in range(len(cases)):
case = cases[i]
blah
I'm running my code in a multi-threaded environment.
Basically, I'm wondering whether Python's for loop's iterating over a set (as in the first for loop) is simply a quickhand way of the second one. What exactly happens when we use the python for loop, and is there any underlying optimization/ implementation that may be causing the behavior difference I'm observing?
No, the second format is quite different.
The for loop calls iter() on the to-loop-over sequence, and uses next() calls on the result. Consider it the equivalent of:
iterable = iter(cases):
while True:
try:
case = next(iterable)
except StopIteration:
break
# blah
The result of calling iter() on a list is a list iterator object:
>>> iter([])
<list_iterator object at 0x10fcc6a90>
This object keeps a reference to the original list and keeps track of the index it is at. That index starts at 0 and increments until it the list has been iterated over fully.
Different objects can return different iterators with different behaviours. With threading mixed in, you could end up replacing cases with something else, but the iterator would still reference the old sequence.
l = [1, 2, 3, 4, 5]
l = iter(l)
while True:
try:
print l.next()
except StopIteration:
exit()
i didn't get any difference,check this below, is it what u exactly trying..
>>> cases = [1,2,3]
>>> for case in cases:
... print case
...
1
2
3
>>> i=0
>>> for i in range(len(cases)):
... print cases[i]
...
1
2
3
>>>
I know about tuple unpacking but what is this assignment called where you have multiple equals signs on a single line? a la a = b = True
It always trips me up a bit especially when the RHS is mutable, but I'm having real trouble finding the right keywords to search for in the docs.
It's a chain of assignments and the term used to describe it is...
- Could I get a drumroll please?
Chained Assignment.
I just gave it a quite google run and found that there isn't that much to read on the topic, probably since most people find it very straight-forward to use (and only the true geeks would like to know more about the topic).
In the previous expression the order of evaluation can be viewed as starting at the right-most = and then working towards the left, which would be equivalent of writing:
b = True
a = b
The above order is what most language describe an assignment-chain, but python does it differently. In python the expression is evaluated as this below equivalent, though it won't result in any other result than what is previously described.
temporary_expr_result = True
a = temporary_expr_result
b = temporary_expr_result
Further reading available here on stackoverflow:
How do chained assignments work? python
#refp's answer is further supported with this output using the dis (disassembly) module:
>>> def a(x):
... g = h = x
...
>>> import dis
>>> dis.dis(a)
2 0 LOAD_FAST 0 (x)
3 DUP_TOP
4 STORE_FAST 1 (g)
7 STORE_FAST 2 (h)
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
The RHS is retrieved and duplicated, then stored into the destination variables left-to-right (try this yourself with e = f = g = h = x).
Some other posters have been confused if the RHS is a function call, like a = b = fn() - the RHS is only evaluated once, and then the result assigned to each successive variable. This may cause unwanted sharing if the returned value is a mutable, like a list or dict.
For those using threading, it is useful to note that there is no "atomicity" implied by the chained assignment form over multiple explicit assignment statements - a thread switch could occur between the assignments to g and h, and another thread looking at the two of them could see different values in the two variables.
From the documentation, 7.2. Assignment statements, g and h being two target lists, x being the expression list:
assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)
An assignment statement evaluates the expression list (remember that this can be a single expression or a comma-separated list, the latter yielding a tuple) and assigns the single resulting object to each of the target lists, from left to right.
OK, "chained assignment" was the search term I was after, but after a bit more digging I think it's not strictly correct. but it is easier to search for than "a special case of the assignment statement".
The Wikipedia article senderle linked to says:
In Python, assignment statements are not expressions and thus do not
return a value. Instead, chained assignments are a series of
statements with multiple targets for a single expression. The
assignments are executed left-to-right so that i = arr[i] = f()
evaluates the expression f(), then assigns the result to the leftmost
target, i, and then assigns the same result to the next target,
arr[i], using the new value of i.
Another blog post says:
In Python, assignment statements do not return a value. Chained
assignment (or more precisely, code that looks like chained assignment
statements) is recognized and supported as a special case of the
assignment statement.
This seems the most correct to me, on a closer reading of the docs - in particular (target_list "=")+ - which also say
An assignment statement evaluates the expression list ... and assigns
the single resulting object to each of the target lists, from left to
right.
So it's not really "evaluated from right-most to left" - the RHS is evaluated and then assigned from left-most target to right - not that I can think of any real-world (or even contrived) examples where it would make a difference.
got bitten by python's Chained Assignment today, due to my ignorance. in code
if l1.val <= l2.val:
tail = tail.next = l1 # this line
l1 = l1.next
what I expected was
tail.next = l1
tail = tail.next
# or equivalently
# tail = l1
whereas I got below, which produce a self loop in the list, leave me in a endless loop, whoops...
tail = l1
tail.next = l1 # now l1.next is changed to l1 itself
since for a = b = c,
one way (python, for example) equivalent to
tmp = evaluate(c)
evaluate(a) = tmp
evaluate(b) = tmp
and have equal right operand for two assignment.
the other (C++, for example) equivalent to
evaluate(b) = evaluate(c)
evaluate(a) = evaluate(b)
since in this case a = b = c is basically
b = c
a = b
and two right hand operand could be different.
That why similar code works well in C++.
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.