6

I have a function that processes file contents, but right now I have the filename hardcoded in the function like this as a keyword argument:

def myFirstFunc(filename=open('myNotes.txt', 'r')): 
    pass

and I call it like this:

myFirstFunc()

I would like to treat the argument as a filename and process the contents.

  1. How do I modify the statement above? I tried this:

    filename=sys.argv[1]  # or is it 0?
    
  2. How do I call it?

MarredCheese
  • 17,541
  • 8
  • 92
  • 91
python4gis
  • 117
  • 1
  • 3
  • 10
  • 3
    Don't use default parameters like that. It will open the file 'myNotes.txt' even if the function is never called. Default parameters should almost always be immutable values. – Steve Howard Jun 23 '11 at 23:51
  • 3
    "I have the filename hardcoded in the function..." No, you don't; you have the file object itself specified as a default parameter. This is a really bad idea. You want to pass the actual name `'myNotes.txt'` to the function, not the `open()` result. Let the body of the function do the `open()` work. – Karl Knechtel Jun 24 '11 at 02:29

3 Answers3

8

something like this:

#!/usr/bin/python3

import sys


def myFirstFunction():
    return open(sys.argv[1], 'r')

openFile = myFirstFunction()

for line in openFile:
    print (line.strip()) #remove '\n'? if not remove .strip()
    #do other stuff

openFile.close() #don't forget to close open file

then I would call it like the following:

./readFile.py temp.txt

which would output the contents of temp.txt

sys.argv[0] outputs the name of script. In this case ./readFile.py

Updating My Answer
because it seems others want a try approach

How do I check whether a file exists using Python? is a good question on this subject of how to check if a file exists. There appears to be a disagreement on which method to use, but using the accepted version it would be as followed:

 #!/usr/bin/python3

import sys


def myFirstFunction():
    try:
        inputFile = open(sys.argv[1], 'r')
        return inputFile
    except Exception as e:
        print('Oh No! => %s' %e)
        sys.exit(2) #Unix programs generally use 2 for 
                    #command line syntax errors
                    # and 1 for all other kind of errors.


openFile = myFirstFunction()

for line in openFile:
    print (line.strip())
    #do other stuff
openFile.close()

which would output the following:

$ ./readFile.py badFile
Oh No! => [Errno 2] No such file or directory: 'badFile'

you could probably do this with an if statement, but I like this comment on EAFP VS LBYL

Community
  • 1
  • 1
matchew
  • 19,195
  • 5
  • 44
  • 48
  • 2
    A note to add to this - One should be careful when retrieving input from the command line. What if the argument is not a valid path to a file? What if there is no argument present? Doesn't matter immediately for this quick example, but it's good to remember for testing and future work. – pseudoramble Jun 23 '11 at 21:46
  • I have to agree with Doug. I would do this a bit differently in production but this may suffice for the question. Anything more may distract from the immediate question. But if this is a simple text manipulation for personal needs this should be all you need. – matchew Jun 23 '11 at 21:47
  • Agreed also. That was more just to point it out for later on. Didn't seem like another answer just for that addition was needed :) – pseudoramble Jun 23 '11 at 21:50
2

For Python 3 you can use the context manager.

# argv[0] is always the name of the program itself.
try:
    filename = sys.argv[1]
except IndexError:
    print "You must supply a file name."
    sys.exit(2)

def do_something_with_file(filename):    
    with open(filename, "r") as fileobject:
        for line in fileobject:
            do_something_with(line)

do_something_with_file(filename)
Keith
  • 42,110
  • 11
  • 57
  • 76
2

This is more than you asked for, but here's a common idiom I use for using command line arguments:

def do_something_with_file(filename):    
    with open(filename, "r") as fileobject:
        for line in fileobject:
            pass    # Replace with something useful with line.

def main(args):
    'Execute command line options.'
    try:
        src_name = args[0]
    except IndexError:
        raise SystemExit('A filename is required.')

    do_something_with_file(src_name)


# The following three lines of boilerplate are identical in all my command-line scripts.
if __name__ == '__main__':
    import sys
    main(sys.argv[1:])  # Execute 'main' with all the command line arguments (excluding sys.argv[0], the program name).
Jon-Eric
  • 16,977
  • 9
  • 65
  • 97
  • Your tuple unpacking is not quite equivalent to the code in your comment, because it will raise an exception if more than one argument is supplied (this is a good side effect, but it will make the given error message slightly incorrect). – Steve Howard Jun 24 '11 at 00:02
  • @Steve Howard, good point. I'll leave that code off until there's more command line parsing. – Jon-Eric Jun 24 '11 at 03:23