my first class: Args

Peter Kleiweg in.aqua.scribis at nl.invalid
Fri Aug 27 10:12:35 EDT 2004


I'm still new to Python. All my experience with OO programming
is in a distant past with C++. Now I have written my first class
in Python. The class behaves exactly as I want, but I would like
to get comments about coding style. I'm especially unsure about
how a class should be documented, what to put in, and where.
When to use double quotes, and when single. For instance, the
doc string at the top must be in double quotes, or else the
pydoc search engine won't find the description. Any
recommendation for other mark-up or meta-data I should include?

I won't tell you what the class is about, because that should be
clear from code documentation. If not, I have work to do. Here
it is:


# -*- coding: iso-8859-1 -*-
"""
Handling of arguments: options, arguments, file(s) content iterator

For small scripts that:
- read some command line options
- read some command line positional arguments
- iterate over all lines of some files given on the command line, or stdin if none given
- give usage message if positional arguments are missing
- give usage message if input files are missing and stdin is not redirected
"""

__author__ = 'Peter Kleiweg'
__version__ = '0.1'
__date__ = '2004/08/27'

import os, sys, getopt

class Args:
    """
    Instance data:
    progname (string) -- name of program
    opt (dictionary) -- options with values
    infile (string) -- name of current file being processed
    lineno (int) -- line number of last line read in current file
    linesum (int) -- total of lines read
    """
    def __init__(self, usage='Usage: %(progname)s [opt...] [file...]') :
        "init, usage string: embed program name as %(progname)s"
        self.progname = os.path.basename(sys.argv[0])
        self.opt = {}
        self.infile = None
        self.lineno = 0
        self.linesum = 0
        self._argv = sys.argv[1:]
        self._argc = len(self._argv)
        self._usage = usage % {'progname': self.progname}

    def __iter__(self):
        "iterator set-up"
        if self._argc == 0 and sys.stdin.isatty():
            self.usage()
        if self._argc == 0:
            self.infile = '<stdin>'
            self._stdin = 1
            self._in = sys.stdin
        else:
            self.infile = self._argv.pop(0)
            self._argc -= 1
            self._stdin = 0
            self._in = open(self.infile, 'r')
        return self

    def next(self):
        "iterator next"
        line = self._in.readline()
        if line:
            self.lineno += 1
            self.linesum += 1
            return line
        self.lineno = -1
        self.infile = None
        if self._stdin:
            raise StopIteration
        self._in.close()
        if self._argc < 1:
            raise StopIteration
        self.lineno = 0
        self.infile = self._argv.pop(0)
        self._argc -= 1
        self._in = open(self.infile, 'r')
        return self.next()

    def warning(self, text):
        "print warning message to stderr, possibly with filename and lineno"
        if self.lineno > 0:
            print >> sys.stderr, '%s:%i: warning: %s' % (self.infile, self.lineno, text)
        else:
            print >> sys.stderr, '\nWarning %s: %s\n' % (self.progname, text)

    def error(self, text):
        "print error message to stderr, possibly with filename and lineno, and exit"
        if self.lineno > 0:
            print >> sys.stderr, '%s:%i: %s' % (self.infile, self.lineno, text)
        else:
            print >> sys.stderr, '\nError %s: %s\n' % (self.progname, text)
        sys.exit(1)

    def usage(self):
        "print usage message"
        print >> sys.stderr, '\n' + self._usage + '\n'
        sys.exit(1)

    def shift(self):
        "pop first of remaining arguments (shift)"
        if self._argc < 1:
            self.usage()
        self._argc -= 1
        return self._argv.pop(0)

    def pop(self):
        "pop last of remaining arguments"
        if self._argc < 1:
            self.usage()
        self._argc -= 1
        return self._argv.pop()

    def getopt(self, shortopts, longopts=[]):
        "get options and merge into dict 'opt'"
        options, self._argv = getopt.getopt(self._argv, shortopts, longopts)
        self.opt.update(dict(options))
        self._argc = len(self._argv)


if __name__ == '__main__':

    a = Args('Usage: %(progname)s [-a value] [-b value] [-c] word [file...]')

    a.opt['-a'] = 'option a'    # set some default option values
    a.opt['-b'] = 'option b'    #
    a.getopt('a:b:c')           # get user supplied option values

    word = a.shift()            # get the first of the remaining arguments
                                # use a.pop() to get the last instead

    for line in a:              # iterate over the contents of all remaining arguments (filenames)
        if a.lineno == 1:
            print 'starting new file:', a.infile
        a.warning(line.rstrip())

    print 'Options:', a.opt
    print 'Word:', word
    print 'Total number of lines:', a.linesum

    print sys.argv              # unchanged

    a.warning('warn 1')         # print a warning
    a.error('error')            # print an error message and exit
    a.warning('warn 2')         # this won't show



-- 
Peter Kleiweg  L:NL,af,da,de,en,ia,nds,no,sv,(fr,it)  S:NL,de,en,(da,ia)
info: http://www.let.rug.nl/~kleiweg/ls.html




More information about the Python-list mailing list