Commands such as cat
read with the file name as an argument, but if no file name is given, the standard input is read. This time I investigated how to achieve this with Python.
$ cat input.txt
$ cat < input.txt
$ python hoge.py input.txt
$ python hoge.py < input.txt
In Python, both the standard input and the pointer to the text file are file objects (more specifically, instances of the _io.TextIOWrapper
class), so the following functions will work even if the standard input sys.stdin
is given as an argument. I will.
def process(fp):
for line in fp:
print(line, end='')
What does this article do with this outside process? With that, we will consider three methods.
hoge.py
import argparse
import sys
def main():
parser = argparse.ArgumentParser()
parser.add_argument('filename', nargs='?')
args = parser.parse_args()
if args.filename is None:
process(sys.stdin)
else:
with open(args.filename) as f:
process(f)
if __name__ == "__main__":
main()
It's a straightforward way to branch depending on whether a command line argument is given. In this article, we do not consider special exception handling for ʻOSError at the time of executing ʻopen ()
or process ()
, but close the file even when an exception occurs in process ()
. Is a mast.
As a supplement to ʻargparsehere, if you omit
nargs ='?',
Filename` will be required.
This method is very easy to understand, but what is not surprising is that process ()
is described in two places. If you devise a little more, you can put it in one place, but if-else still feels a little redundant.
hoge.py
import argparse
import sys
def main():
parser = argparse.ArgumentParser()
parser.add_argument('infile', nargs='?', type=argparse.FileType(),
default=sys.stdin)
args = parser.parse_args()
with args.infile as f:
process(f)
It's a little unfamiliar, but overall it's very refreshing.
By setting type = argparse.FileType ()
, ʻopen ()is called at the moment of
parse_args ()and its return value is stored. At this time, if the given file name is
-, it will be converted to standard I / O. Therefore, if you set
default ='-', the description will be reduced a little and ʻimport sys
will be unnecessary, but it is difficult for strangers to understand, and [Document example](https://docs. python.org/ja/3/library/argparse.html) also explicitly states default = sys.stdin
.
And it is normal to write ʻopen ()immediately after
with, but the return value is the same even for the file object itself, so the operation is the same. Although the significance of using ʻas
is diminished.
sys.stdin
is usually not bothered to be used with the with
statement or to call close ()
, but it is well defined because it is a TextIOWrapper. Probably it is used in such a case. (Citation needed)
fileinput
module together.hoge.py
import argparse
import fileinput
def main():
parser = argparse.ArgumentParser()
parser.add_argument('filenames', nargs='*')
args = parser.parse_args()
with fileinput.input(args.filenames) as f:
process(f)
fileinput.input ()
opens the enumerated file names one after another and converts them to standard input if no file name is given.
Even if -
is specified as the file name, the standard input is called, so if you execute $ python hoge.py input.txt -
etc., the standard input will be read after reading input.txt. Well this won't be a big deal!
Personally, I think the difficulty is that this fileinput module seems to support standard input if you don't know it. There is no place. I don't think this is such a famous module ...
I think it's best to use method 2 when reading a single file ** or ** standard input, and method 3 when reading multiple files ** or ** standard input.
(11/23 postscript) Click here if you want to read multiple files at the same time → [How to read standard input or variable files at the same time like the paste command in Python](https://qiita.com/hi-asano/ items / de83b18ce4365dd6f793)
If you try to do the same thing in another language, you usually have to do it with if-else like 1, which is quite difficult? Perl seems to be easy.
Recommended Posts