When I printed a list, I got a syntax error when using this method:
print i for i in [1,2,3]
I knew this is ok when using this method:
for i in [1, 2, 3]:
print i
and I knew that
(i for i in [1, 2, 3])
is a generator object, but I just don't get it that why
print i for i in [1, 2, 3]
does't work. Can anyone give me a clue?
The list comprehension syntax x for x in ... requires brackets around it. That's a syntactic rule of Python, just like requiring indentation, or requiring a colon after if or whatever. i for i in [1, 2, 3] by itself is not valid syntax. You need either [i for i in [1, 2, 3]] (for a list comprehension) or (i for i in [1, 2, 3]) (for a generator comprehension).
In Python 2, print is a statement, not an expression or a function, so you can't use it directly in a comprehension. Use this trick:
def f(x): print x
[f(i) for i in [1,2,3]]
Note that (f(i)...) doesn't work because this just creates a generator which would call f() if you iterated over it. The list comprehension [] actually invokes f().
[EDIT] If you use Python > 2.6, you can achieve the same using
from __future__ import print_function
[print(i) for i in [1, 2, 3]]
Note the () around the argument to print.
The list comprehension syntax ([expression for loop]) is a shorthand loop syntax for producing a list.
You are not producing a list, you want to print items in a loop. Since you are not producing a python list, you have to use a regular loop.
Alternatively, since all you are doing is printing the items on separate lines, just add the newlines yourself:
print '\n'.join(i for i in [1, 2, 3])
This produces the same output as:
for i in [1, 2, 3]:
print i
If you use Python 3, or use from __future__ import print at the top of your module and so use the print() function, you can send all values to the function in one call, and tell print() to use newlines in between:
values = [1, 2, 3]
print(*values, sep="\n")
As an expression (in the grammar):
[i for i in [1, 2, 3]] is a list comprehension.
(i for i in [1, 2, 3]) is a generator expression.
But i for i in [1, 2, 3] by itself is a syntax error, and that's just the way it is. There must be something surrounding it. Unless you have ( or [ around it, it's not a valid expression, because the for keyword is not valid at that point.
Inside the print statement, it wants an expression.
(As a red herring, func(i for i in [1, 2, 3]) is permitted as an expression, being a function call with the first argument being a generator expression.)
Print is not a function, it's a statement, and you can't have them in expressions. Just use a regular loop as you don't want to produce a list, that a list comprehension does. In theory you can do (not that you should. at all):
from __future__ import print_function
[print(my_item) for my_item in [1,2,3,4]]
1
2
3
4
Out[26]:
[None, None, None, None]
This is invalid python syntax. The i for i in [1, 2, 3] is only valid in a list or generator comprehension, ie. surrounded by [] or () respectively.
You'll want to use:
print '\n'.join(str(i) for i in [1, 2, 3])
Related
It looks e for e in [1, 2, 3, 4, 5] is a generator expression and (e for e in [1, 2, 3, 4, 5]) is evaluated as an generator object. Hence, I think (...) is evaluation in Python.
I suppose list(e for e in [1, 2, 3, 4, 5]) is telling the Python runtime to evaluate the iterable expression, generate its object(s), and call the list function to invoke yield until it runs out of elements.
print(list(e for e in [1, 2, 3, 4, 5]))
---
[1, 2, 3, 4, 5]
Question
What actually is [...] in the code below and what is its mechanism? [ e for e in [1, 2, 3, 4, 5] ] generates a list object, hence I suppose it is a combination of an evaluation on e for e in [1, 2, 3, 4, 5] to create a generator object and invoking a call to the generator object. Is it a alias of a function call to list(...)?
print([ e for e in [1, 2, 3, 4, 5] ])
---
[1, 2, 3, 4, 5]
For the list access with a slice object, I suppose [1:3] is telling Python to evaluate the 1:3 expression to generate a slice object.
print([1,2,3][1:3])
print([1,2,3][slice(1,3,1)])
---
[2, 3]
[2, 3]
[(1:3)] fails because it tries to evaluate already evaluated 1:3?
print([1,2,3][(1:3)])
---
File "<ipython-input-167-c20e211025dc>", line 1
print([1,2,3][(1:3)])
^
SyntaxError: invalid syntax
[1, 2, 3, 4, 5] is a list literal.
value for item in iterable is a generator comprehension. list(value for item in iterable) would be calling the list() constructor with a generator, which of course just produces a list. For the purpose of reducing ambiguity, the generator comprehension cannot be used naked. But it can be used either inside a set of parentheses, or inside another expression, such as a parameter in a function call. A similar limitation applies to the := (walrus) operator added in Python 3.8.
[value for item in iterable] is a list comprehension. Note that Python treats this as an entirely separate syntactic construct.
The implementations are probably about the same, but as far as I'm aware the Python compiler detects the generator comprehension and the list comprehension separately while it processes the code, and the list comprehension is not defined as a subset/special case of either a generator comprehension or a list literal.
I'm pretty sure a similar thing applies to slice syntax - it's defined as its own syntax, specifically in the context of list indexing, and in no other context. lst[1:3] getting compiled into lst.__getitem__(slice(1, 3)) is part of the compilation process, and is not a general thing for the syntax 1:3 (as that's ambiguous).
In other words, if I remember correctly, lst[x:y:z] is a different syntactic construct from lst[x], as far as the Python compiler is concerned.
*The information in this post is based on my understanding and prior interaction with various methods in the CPython source code. I'm drawing some conclusions between the syntax, the compiler, and the compiled code that may not be valid.
The for operator can also be used as an expression, like in
print(c for c in iter)
The python language reference makes no mention of this, or at least I could not find it.
Is the value of this expression well defined, and is the a point of using it?
EDIT: I wrote this from the smartphone, but now that I'm back to the code I saw this in, I noticed an error as pointed out in the comments - I added the c in front of for.
This form of for loop is called a generator object, from here:
Generator functions allow you to declare a function that behaves like
an iterator, i.e. it can be used in a for loop.
Also
Generator expressions provide an additional shortcut to build
generators out of expressions similar to that of list comprehensions.
In fact, we can turn a list comprehension into a generator expression
by replacing the square brackets ("[ ]") with parentheses.
Alternately, we can think of list comprehensions as generator
expressions wrapped in a list constructor.
example:
>>> (x for x in range(10))
<generator object <genexpr> at 0x0000014DEA749E08>
You can use the starting * character to print the all values of an iterator.
Code:
my_list = [1, 2, 3, 4, 5]
print(*my_list, sep="\n")
Output:
>>> python3 test.py
1
2
3
4
5
Or you can make more complex expressions with * character and list comprehension.
Code:
my_list = [1, 2, 3, 4, 5]
print(*[x for x in my_list if x > 2], sep="\n")
Output:
>>> python3 test.py
3
4
5
NOTE:
You can print the generator object as well, like this:
Code:
my_list = [1, 2, 3, 4, 5]
print(x for x in my_list)
Output:
>>> python3 test.py
<generator object <genexpr> at 0x7f614ded7d58>
I want to perform the following:
>>> [0-2, 4] #case 1
[-2, 4] #I want the output to be [0, 1, 2, 4]
I know I can perform the same in this way:
>>> list(range(3)) + [4] #case 2
[0, 1, 2, 4]
But I am curious is there any way to achieve the same result using the case 1 method (or something similar)? Do I need to override the integer '-' operator or do I need to do anything with the list?
>>> [*range(0,3), 4]
[0, 1, 2, 4]
Should come closest. Python 3 only.
The answer by #timgeb is great, but this returns a list, and by default range returns an "an immutable sequence type" and so using itertools.chain would give an iterable that is more closely related to range().
import itertools
itertools.chain(range(3), range(4,5))
which (once converting to a list with list() so we can see the contents) would give:
[0, 1, 2, 4]
Or you could make your own generator:
def joinRanges(r1, r2):
for i in r1:
yield i
for i in r2:
yield i
which achieves the same effect as before when calling with:
joinRanges(range(3), range(4,5))
This question already has answers here:
Why do these list operations (methods: clear / extend / reverse / append / sort / remove) return None, rather than the resulting list?
(6 answers)
Closed 5 months ago.
Working my way into Python (2.7.1)
But failing to make sense (for hours) of this:
>>> a = [1, 2]
>>> b = [3, 4]
>>>
>>> a.extend([b[0]])
>>> a
[1, 2, 3]
>>>
>>> a.extend([b[1]])
>>> a
[1, 2, 3, 4]
>>>
>>> m = [a.extend([b[i]]) for i in range(len(b))] # list of lists
>>> m
[None, None]
The first two extends work as expected, but when compacting the same in a list comprehension it fails.
What am i doing wrong?
extend modifies the list in-place.
>>> [a + b[0:i] for i in range(len(b)+1)]
[[1, 2], [1, 2, 3], [1, 2, 3, 4]]
list.extend() extends a list in place. Python standard library methods that alter objects in-place always return None (the default); your list comprehension executed a.extend() twice and thus the resulting list consists of two None return values.
Your a.extend() calls otherwise worked just fine; if you were to print a it would show:
[1, 2, 3, 4, 3, 4]
You don't see the None return value in the Python interpreter, because the interpreter never echoes None results. You could test for that explicitly:
>>> a = []
>>> a.extend(['foo', 'bar']) is None
True
>>> a
['foo', 'bar']
the return value of extend is None.
extend function extends the list with the value you've provided in-place and returns None. That's why you have two None values in your list. I propose you rewrite your comprehension like so:
a = [1, 2]
b = [3, 4]
m = [a + [v] for v in b] # m is [[1,2,3],[1,2,4]]
For python lists, methods that change the list work in place and return None. This applies to extendas well as to append, remove, insert, ...
In reply to an older question, I sketched an subclass of list that would behave as you expected list to work.
Why does [].append() not work in python?
This is intended as educational. For pros and cons.. look at the comments to my answer.
I like this for the ability of chaining methods and working in a fluent style, e.g. then something like
li = FluentList()
li.extend([1,4,6]).remove(4).append(7).insert(1,10).reverse().sort(key=lambda x:x%2)
would be possible.
a.extend() returns None.
You probably want one of these:
>>> m = a + b
>>> m
[1, 2, 3, 4]
>>> a.extend(b)
>>> a
[1, 2, 3, 4]
Aside from that, if you want to iterate over all elements of a list, you just can do it like that:
m = [somefunction(element) for element in somelist]
or
for element in somelist:
do_some_thing(element)
In most cases there is no need to go over the indices.
And if you want to add just one element to a list, you should use somelist.append(element) instead of `somelist.extend([element])
Normally, list comprehensions are used to derive a new list from an existing list. Eg:
>>> a = [1, 2, 3, 4, 5]
>>> [i for i in a if i > 2]
[3, 4, 5]
Should we use them to perform other procedures? Eg:
>>> a = [1, 2, 3, 4, 5]
>>> b = []
>>> [b.append(i) for i in a]
[None, None, None, None, None]
>>> print b
[1, 2, 3, 4, 5]
or should I avoid the above and use the following instead?:
for i in a:
b.append(i)
You should indeed avoid using list comprehensions (along with dictionary comprehensions, set comprehensions and generator expressions) for side effects. Apart from the fact that they'd accumulate a bogus list and thus waste memory, it's also confusing. I expect a list comprehension to generate a (meaningful) value, and many would agree. Loops, on the other hand, are clearly a sequence of statements. They are expected to kick off side effects and generate no result value - no surprise.
From python documentation:
List comprehensions provide a concise way to create lists. Common
applications are to make new lists
Perhaps you want to learn more about reduce(), filter() and map() functions.
In the example you give it would make the most sense to do:
b = [i for i in a]
if for some reason you wanted to create b. In general, there is some common sense that must be employed. If using a comprehension makes your code unreadable, don't use it. Otherwise go for it.
Only use list comprehensions if you plan to use the created list. Otherwise you create it just for the GC to throw it again without ever being used.
So instead of [b.append(i) for i in a] you should use a proper for loop:
for i in a:
b.append(i)
Another solution would be through a generator expression:
b += (i for i in a)
However, if you want to append the whole list, you can simply do
b += a
And if you just need to apply a function to the elements before adding them to the list, you can always use map:
b += map(somefunc, a)
b = []
a = [1, 2, 3, 4, 5]
b.extend (a)