Learn more python the hardway ex 12

Hello again,

I have followed the advice of both Florian and Zed, and started in the learnmorepythonthehardway book plus a machinelearning book.

Now in lmpthw ex12 It is asked to integrate some of the tools that I made into one big module ready for import. But since I have been working with argparse since the start, I noticed that it is hard to import a module that also needs commandline arguments to be parsed. If you see the following:

import re
import argparse

def parse_args():

    parser = argparse.ArgumentParser()

    parser.add_argument('replace', type=str, help="string to replace")
    parser.add_argument('substitute', type=str, help="replacement")
    parser.add_argument('file', type=str, help="In which file?")
    parser.add_argument('-r', '--reg', action = 'store_true')

    return parser.parse_args()

def sed(args):

    if args.reg:
        hello = open(args.file, "r")
        newfile = open("new_file.txt", "w")

        for line in hello:
            x = re.sub(args.replace,args.substitute, line)
            newfile.write(x)

        newfile.close()

        newfile = open("new_file.txt", "r")

        content = newfile.read()
        print(content)




    else:
        hello = open(args.file, "r")
        newfile = open("new_file.txt", "w")

        for line in hello:
            newfile.write(line.replace(args.replace, args.substitute))

        newfile.close()

        newfilex = open("new_file.txt", "r")

        content = newfilex.read()
        print(content)

sed(parse_args())

The code is not really usable when imported, except for if you intend to use it exactly in the same way as you would if you would just run the standalone file.

It is easier to work with a sys.argv file like so:

import sys


def tail():
    for file in sys.argv[1:]:
        linesread = open(file, "r").readlines()
        for line in linesread[-10:]:
            print(line)

Are there any tips for making an imported file that uses argparse more flexible?

Also, the book talks a lot about list comprehension for for-loops. Is there any way in which I can make the tail function smaller with such a comprehension?

Yes, you need individual argument parsers for each tool. I think you have a few options here.

You can rename the individual parse_args functions to something like tail_parse_args, cat_parse_args etc. to avoid name clashes.

Or use classes to encapsulate the arg parsing details. Something like this should work:

class Tail(object):
    def __parse_args(self, args):
        # parse args with argparse...
        self.path, self.num_lines = ...

    def run(self, args):
        self.__parse_args(args)
        with open(self.path, "r") as f:
            for l in f.readlines()[-self.num_lines:]:
                print(l, end="")

Then in your main module you can just import the class.

This is a use case where classes make a lot of sense because they allow you to tightly couple related parts of your module and hide implementation details.

I don’t see how this would make sense here. After all, you’re not gathering a list, but you get one with zero hassle from readlines and then just print it.

But you’ll want to close your file after reading and printing it. Take a look at the with statement in my snippet above.

Much appreciated! <3

A free service run by Zed A. Shaw for learncodethehardway.org.