24

I am trying to get multiple names separated by newlines from the console and put them into a variable. Let's assume I want to get input from the terminal forever (I'll add some code to break out of the loop later). I know how to do it with a while loop and recursion, but I would like to be able to do it with a for loop.

In the below example when I get "peter" as input from the terminal I get each letter rather than a whole line at a time:

for name in input():
    print(name)

Now, if I use sys.stdin the name variable becomes "peter\n":

for name in sys.stdin:
    print(name)

Is there a easy way to get input() to give "name" a whole line rather than individual characters? Or just by the nature of using for in I am going to be iterating through the characters in the input? Are there any inherent risks/problems with getting input in this fashion? Is there a "standard" way of getting input in a situation like this?

I am using Python 3.5.1 on Ubuntu 15.10.

6
  • input() returns a string which is an iterable, so therefore when you try and iterate over it you are getting each character one by one. Commented Jan 30, 2016 at 1:18
  • Ok that makes sense. input() returns a string. So does sys.stdin return a buffer that is iterated line by line? Commented Jan 30, 2016 at 1:20
  • Because sys.stdin returns a file like object which, when iterated through, will contain each individual line of the input. Commented Jan 30, 2016 at 1:23
  • 1
    @PeterH sys.stdin isn't a function, it actually is a file object which is used by the system to get the standard input, therefore for name in sys.stdin behaves like it would do on a file: reading it line by line. Commented Jan 30, 2016 at 1:23
  • Cool makes sense. If I am using 'for name in sys.stdin' that would exit the loop when the input ends correct? Commented Jan 30, 2016 at 1:26

2 Answers 2

27

You can wrap stdin to strip the newlines; if you can strip all trailing whitespace (usually okay), then it's just:

for name in map(str.rstrip, sys.stdin):
    ...

You're on Py3, so that works as is; if you're on Py2, you'll need to add an import, from future_builtins import map, so you get a lazy, generator based map (that yields the lines as they're requested, rather than slurping stdin until it ends, then returning a list of all the lines).

If you need to limit to newlines, a generator expression can do it:

for name in (line.rstrip("\r\n") for line in sys.stdin):
    ...

or with an import to allow map to push work to C layer for (slightly) faster code (a matter of 30-some nanoseconds per line faster than the genexpr, but still 40 ns per line slower than the argumentless option at the top of this answer):

from operator import methodcaller

for name in map(methodcaller('rstrip', '\r\n'), sys.stdin):
    ...

Like the first solution, on Py2, make sure to get the map from future_builtins.

Sign up to request clarification or add additional context in comments.

Comments

3

I wouldn't recommend you this, but you can create a generator to be used in a for loop to iterate through input line by line:

def getlines():
    while True:
        yield input()

for name in getlines():
    print(name)
    ## Remember to break out of the loop at some point

2 Comments

Sorry if I was unclear. I am trying to do it more than one time with each name separated by a newline in the terminal.
This seems perfect for the simplest line-by-line reading. And the iterator could be enhanced to split that line into smaller parts, yielding those parts one by one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.