[Tutor] working code for adding line numbers -- request for criticism

Lloyd Kvam pythonTutor at venix.com
Sat Apr 17 17:18:35 EDT 2004


On Sat, 2004-04-17 at 15:56, Brian van den Broek wrote:
> Hi all,
> 
> having learned the lessons of posting under-thought-out questions and not 
> wishing to further test the goodwill of those on the list, I have code to post 
> this time! (Thanks again for past tolerance.)
> 
> I've found that traceback errors identified by line numbers can be tricky to 
> track down without line number indications in the code or the editor. (IDLE 
> doesn't seem to provide for line numbers, and it's no fun counting line on 
> screen in a long file.) 

Use Alt-G to jump to a line.  (Works for me in Linux & WinNT)

> So, I wrote a script to take a file and output a file 
> with line number comments added. (BTW, is there a module that will do this? If 
> so, no harm, as the exercise was useful, but I'd probably be better off with a 
> module than my script.)
> 
> I've worked through a way to do it. But I'd very much appreciate being told 
> where and how this code is kludgey and could be improved. As I said, it seems to 
> work, but I don't think it will win any prizes for beauty or being Pythonic. If 
> asking for such a critique is over-imposing, I understand. (My aim in asking is 
> to break bad habits before they become entrenched. Brutal criticism is happily 
> accepted.)
> 
The fileinput module makes it easy to process lists of input files or
piped input through stdin.  That's usually better than prompting for
filenames in your program.

> Right near the top, there is a comment where I have a question about how to do 
> it better.

Use triple quotes for multi-line strings.  These can break the indent
rules.  I adjusted your code down below.

One other thing to note, Python now has an enumerate function which will
provide a counter as you iterate.  This allows you to write:

for i,line in enumerate(sfile):

and helps avoid errors where you forget to initialize the counter or
fail to increment the counter.

> 
> One case where I know it does not work is for files without any extension at 
> all. I want file.txt to come out as file_numbered.txt but file comes out as 
> fil_numberede. I can see how to fix that (by constructing the output filename 
> differently depending on whether the filename contains a '.' or not, but it 
> didn't seem worth doing.
> 
> I also understand that adding comments to arbitrary lines may violate syntax 
> (say, by adding a comment to other than the last line of a long string). It also 
> may well take lines past 80 characters. Neither worry me; the line number 
> comments are being added to a new file intended for inspection rather than 
> running. Also, it is likely OS specific to DOS/Windows. That's what I run (for 
> now) and what I can test on.
> 
> Thanks and best to all,
> 
> Brian vdB
> 
> -----
> import os.path
> 
> def get_filename():
       filename_prompt = '''What file would you like to process?
(Specify a full path if it is not in the current working directory)
'''
>      f = raw_input(filename_prompt)
>      # This makes for ugly screen output. How can I left allign the output
>      # without breaking the function def's indetation?
>      return f
> 
> def get_multiple():
>      print
>      m = raw_input('By default, I mark each %i lines with line numbers.\n \
>      Would you like a different choice of line multiples to mark?  \n \
>      If so, enter a positive whole number now. \n \
>      (All other choices will result in the use of the default value of %i)\
>      \n' %(default, default))
>      o = 'Your input was not a positive integer. \n \
>      The default multiple of %i will be used instead' %default
>      try:
>          m = int(m)
>          if m > 0: return m
>          else:
>              print o; return default
>      except:
>          print o; return default
> 
> default  = 5
> print
> print 'Yout current working directory is ' + os.getcwd()
> print
> 
> sfilename = get_filename()
> # 'sfilename', etc. for source file name, etc.
> # Likewise for 'tfilename' and taget file name.
> print
> while os.path.isfile(sfilename) == False:
>      print "I'm sorry, but you have specified a non-existent file path.\
>      Please try again. (You can press CTRL-C to end if you prefer)"
>      sfilename = get_filename()
> 
> multiple = get_multiple()
> print
> 
> sfile = file(sfilename)
> sfile_base = os.path.basename(sfilename)
> i = sfile_base.rfind('.')
> tfile_base = sfile_base[:i] + '_numbered' + sfile_base[i:]
> # inserts '_numbered' immediately before the extension (if any) of the filename
> # otherwsie before the last character. A bit broken, but doesn't matter.
> tfilename = os.path.join(os.path.dirname(sfilename), tfile_base)
> 
> # Prints output file name and location
> #
> if os.path.dirname(tfilename) == '': dirname = os.getcwd()
> # To ensure that the directory is displayed in print below. Needed as
> # os.path.dirname(tfilename) == '' when the dirname is the cwd
> else: dirname = os.path.dirname(tfilename).capitalize()
> # Capitalize ensures that drive letter displays in DOS convention
> target = (tfile_base, dirname)
> print 'Your numbered file will be %s in the directory %s' %target
> 
> tfile = file(tfilename, 'w')
> i = 1
> for line in sfile:
>      if i%multiple == 0 and line[-1] == '\n':
>          line = line[:-1] + '  # ' + str(i) + '\n'
>      if i%multiple == 0 and line[-1] != '\n':
>          line = line + '  # ' + str(i)
>      tfile.write(line)
>      i = i + 1
> 
> tfile.close()
> sfile.close()
> 
> 
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> http://mail.python.org/mailman/listinfo/tutor
-- 

Lloyd Kvam
Venix Corp.
1 Court Street, Suite 378
Lebanon, NH 03766-1358

voice:	603-653-8139
fax:	801-459-9582




More information about the Tutor mailing list