23

I write a lot of little scripts that process files on a line-by-line basis. In Perl, I use

while (<>) {
    do stuff;
}

This is handy because it doesn't care where the input comes from (a file or stdin).

In Python I use this

if len(sys.argv) == 2: # there's a command line argument
    sys.stdin = file(sys.argv[1])
for line in sys.stdin.readlines():
    do stuff

which doesn't seem very elegant. Is there a Python idiom that easily handles file/stdin input?

Eisen
  • 450
  • 4
  • 11
  • 1
    From a "readable code" point of view, I'd prefer your Python code as most people not working with Perl won't know what the Perl code means. – schnaader Apr 30 '09 at 14:28
  • 4
    You can at least omit .readlines() – Jiri Apr 30 '09 at 14:30
  • 2
    Duplicate: http://stackoverflow.com/questions/715277/how-do-i-iterate-over-all-lines-of-files-passed-on-the-commandline-in-python – S.Lott Apr 30 '09 at 14:31
  • The perl version isn't elegant, its just shorter. Like schnaader said, its highly unreadable to anyone who doesn't know perl. – Soviut Apr 30 '09 at 14:31
  • 9
    French is highly unreadable to anyone who doesn't know French. – Eisen Apr 30 '09 at 14:42
  • 8
    Ah, yes, but the python is somewhat readable to someone who knows English :) – Noah Apr 30 '09 at 22:23
  • the statement "French is highly unreadable to anyone who doesn't know French" is wrong, if you know latin ! – Blauohr May 06 '09 at 11:00
  • `for line in sys.stdin.readlines():` is a bad example, as it reads the whole file into memory and creates a list of strings. Using the line iterator in the file is better practice: `for line in sys.stdin:` – clacke Mar 12 '15 at 14:36

3 Answers3

51

The fileinput module in the standard library is just what you want:

import fileinput

for line in fileinput.input(): ...
Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • Indeed. Thanks a million. Sorry I missed the other question that deals with the same problems. Was hard to find with this tite... – Eisen Apr 30 '09 at 14:40
15
import fileinput
for line in fileinput.input():
    process(line)

This iterates over the lines of all files listed in sys.argv[1:], defaulting to sys.stdin if the list is empty.

RichieHindle
  • 272,464
  • 47
  • 358
  • 399
  • I'm using the arguments for other purposes, can I disable that behavior? – user1552512 Apr 09 '13 at 21:31
  • @user1552512 Yes, see https://docs.python.org/2/library/fileinput.html : `To specify an alternative list of filenames, pass it as the first argument to input(). A single file name is also allowed.` – clacke Mar 12 '15 at 14:39
7

fileinput defaults to stdin, so would make it slightly more concise.

If you do a lot of command-line stuff, though, this piping hack is very neat.

Mark
  • 6,269
  • 2
  • 35
  • 34