简体   繁体   中英

Why print cannot be used with for on the same line in python 2/3?

I would love to implement the following:

print(i) for i in xrange(10)

However, this does not work in neither python2 nor python3. What is the limitation of the language? Or what did I do wrong?

Like this:

for i in xrange(10): print(i)

You could also do something like this, but only in Python 3 where print is a function. This is an abuse of generator expressions, though.

any(print(i) for i in range(10))

Set builder notation (called generator expressions in Python) only work when you are building a set. The notation you are using is set builder notation (generator expressions) (something like x for x in range(10) if ... ). That being said, you can use a regular for loop

for i in xrange(10):
    print(i)

or set builder notation building an empty set:

>>> x = [print(i) for i in xrange(10)]
0
1
2
3
4
5
6
7
8
9
>>> x
[None, None, None, None, None, None, None, None, None, None]
>>> 

The reason the set has all the none values is because you are never adding to the set, but only printing stuff out.

The form x for x in <sequence> is meant to result in a list. It was originally this:

>>> [i for i in range(10)] 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

introduced in Python 2.0, Python Enhancement Proposal 202 , coming from a variation of uses of map() and filter(). Those functions, and list comprehensions, originate with functional programming environments, which tend to lean towards no-side-effects and no-surprise-state-changes and so on.

In the case where list comprehensions support a function call, it's intended for something like this simple transformation:

>>> [math.sin(x) for x in whatever]
[0.1, 0.2, ...]

The function is intended to change one list item into a new list item - and the output is still a list.

This syntax lost the surrounding brackets [ ] a couple of years later in PEP289 as they became more memory-efficient Generator Comprehensions in Python 2.4. These are intended for when you don't need the full list output as a list because you are processing all the contents as soon as you get them - eg sum(i for i in range(10)) can add up all the numbers as they appear, without waiting for the full sequence to finish computing first.

The way you want to use it - print(x) for x in <sequence> is in the form of a generator comprehension, but you don't want the generator, the list, the sequence. You only want to do it for a side effect which happens when you call the function.

That's not impossible, you can do this in Python 2

import sys
[sys.stdout.write(str(i) + '\n') for i in range(10)]

and as @wim notes in a comment, this in Python 3:

[print(i) for i in range(10)]

However, print() doesn't return anything useful, the newly built list or generator is irrelevant and immediately thrown away.

This structure is confusing/misleading to people reading your code, you are explicitly using the "I want to build a list" format when you don't want to build a list.

It's also against the original ideas of list comprehensions and their origins in functional programming - it's much easier to reason about things when they don't have side effects.

From the Zen of Python :

  • Explicit is better than implicit.

If you want to iterate over a sequence and print something, explicitly iterate over a list and print it ( for item in sequence: print(item) ). Don't start with "I'm going to build a new list, oh I sneakily printed something as a side effect, then threw the list away".

It's hard to read your intent - did you mean to do that? What did you want it to do?

It's harder to explain - what does this code do? "It builds a new list of None s which are the return values from printing the list items". That's putting the focus of what's happening in all the wrong places.

Your attempt is syntactically incorrect but you can do actually do it in one line using print as a function and do it without the need for the explicit for loop:

print(*range(10), sep="\n")

Would be equivalent to:

 for i in range(10):
    print(i)

and output:

In [32]: print(*range(10),sep="\n")
0
1
2
3
4
5
6
7
8
9
In [2]: print(*range(10))
0 1 2 3 4 5 6 7 8 9

And in python2 you just need to import print_function :

from __future__ import print_function

In [3]: print(*xrange(10),sep="\n")
0
1
2
3
4
5
6
7
8
In [4]: print(*xrange(10))
0 1 2 3 4 5 6 7 8 9

or using str.join :

print("\n".join(map(str,range(10))))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM