473,321 Members | 1,748 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,321 software developers and data experts.

ESR's fortune.pl redone in python - request for critique

I have recently completed a mini-project with the goal of rewriting
in Python Eric Raymond's fortune.pl script
(http://www.catb.org/~esr/fortunes/fo...onfuse-apache),
except that instead of generating a sigline for mail, it prints a
fortune to screen in the traditional manner of the Unix fortune. I
have succeeded in terms of functionality, but because I am only a
novice programmer, I would appreciate any comments, criticism,
suggestions, alternative options, etc. that more experienced
programmers would be willing to give, whether technical or stylistic
in nature. Here is my code:

#! /usr/bin/env python

## fortune
## Jeremy Conn
## Version 0.9, 20020329
## GNU GPL http://www.fsf.org/licenses/gpl.html
## Description: Generates a random fortune for display onscreen from
## a single file of quotes which the user maintains; the
## quotes can be multi-line, and are separated by lines
## containing only a percent sign (same format as
## traditional fortune files).

import random
import re
import sys

FORTUNES_FILE = ".fortune"

# What file should we use?
if len(sys.argv) > 1:
fortunes_file = sys.argv[1]
else:
fortunes_file = FORTUNES_FILE

# Let's see if we can open that file for reading
try:
fi = open(fortunes_file, 'r')
except:
sys.exit("Cannot open fortunes file %s." % fortunes_file)

# Collect the file pointers to each fortune entry in the file
fp_entry = [0]
line = fi.readline()
while line != "":
if re.match(r'^%$', line):
fp_entry.append(fi.tell())
line = fi.readline()

# Seek to a random entry
try:
fi.seek(random.choice(fp_entry))
except:
sys.exit("Cannot seek.")

# Add the entry to output message and then print it
fortune = ''
line = fi.readline()
while line != '':
if re.match(r'^%$', line):
break
fortune += line
line = fi.readline()
print fortune

# Return fp to beginning of file, close the file, and exit program
fi.seek(0,0)
fi.close()
sys.exit()

- Jeremy
ad**************@yahoo.com

__________________________________
Do you Yahoo!?
Yahoo! Finance Tax Center - File online. File on time.
http://taxes.yahoo.com/filing.html

Jul 18 '05 #1
5 1686
P
Adelein and Jeremy wrote:
I have recently completed a mini-project with the goal of rewriting
in Python Eric Raymond's fortune.pl script
(http://www.catb.org/~esr/fortunes/fo...onfuse-apache),


I did a very quick fortune file parser as part of:
http://www.pixelbeat.org/rotagator

Pádraig.
Jul 18 '05 #2

I would appreciate any comments, criticism, suggestions, alternative
options, etc.
Here are some random comments; needless to say they represent my
subjective view. Others mitht disagree heartily!

FORTUNES_FILE = ".fortune"

# What file should we use?
if len(sys.argv) > 1:
fortunes_file = sys.argv[1]
else:
fortunes_file = FORTUNES_FILE
Using the same variable name with only difference in capitalization I
consider very bad taste. I would suggest using for instance the
variable name 'default_fortunes_file' instead of FORTUNES_FILE.

fp_entry = [0]
You probably want to start with an *empty* list, not a list with '0'
as the first element, i.e.

fp_entry = []
fortune = ''
line = fi.readline()
while line != '':
if re.match(r'^%$', line):
break
fortune += line
line = fi.readline()
print fortune
Wouldn't it be more natural to look for '%' instead of blank lines:

<Untested>
fortune = ''
line = fi.readline()
while line:
if re.match(r'^%$',line):
break
fortune += line
line = fi.readline()
</Untested>
# Return fp to beginning of file, close the file, and exit program
fi.seek(0,0)
fi.close()
sys.exit()


I like to close the files explicitly, like you do. However it is not
really necessary, they are closed automatically (by the garbage
collector I guess).

Repositioning the


--
/--------------------------------------------------------------------\
/ Joakim Hove / ho**@bccs.no / (55 5) 84076 | \
| Unifob AS, Avdeling for Beregningsvitenskap (BCCS) | Stabburveien 18 |
| CMU | 5231 Paradis |
\ Thormøhlensgt.55, 5020 Bergen. | 55 91 28 18 /
\--------------------------------------------------------------------/
Jul 18 '05 #3
Adelein and Jeremy wrote:
I have recently completed a mini-project with the goal of rewriting
in Python Eric Raymond's fortune.pl script
(http://www.catb.org/~esr/fortunes/fo...onfuse-apache),
except that instead of generating a sigline for mail, it prints a
fortune to screen in the traditional manner of the Unix fortune. I
have succeeded in terms of functionality, but because I am only a
novice programmer, I would appreciate any comments, criticism,
suggestions, alternative options, etc. that more experienced
programmers would be willing to give, whether technical or stylistic
in nature. Here is my code:

#! /usr/bin/env python

## fortune
## Jeremy Conn
## Version 0.9, 20020329
## GNU GPL http://www.fsf.org/licenses/gpl.html
## Description: Generates a random fortune for display onscreen from
## a single file of quotes which the user maintains; the
## quotes can be multi-line, and are separated by lines
## containing only a percent sign (same format as
## traditional fortune files).

import random
import re
import sys

FORTUNES_FILE = ".fortune"

# What file should we use?
if len(sys.argv) > 1:
fortunes_file = sys.argv[1]
else:
fortunes_file = FORTUNES_FILE

# Let's see if we can open that file for reading
try:
fi = open(fortunes_file, 'r')
except:
Make it a rule to catch something, e. g.

try:
...
except IOError:
...

That reduces the chance that an unexpected error is mapped to something
else.

sys.exit("Cannot open fortunes file %s." % fortunes_file)

# Collect the file pointers to each fortune entry in the file
fp_entry = [0]
line = fi.readline()
while line != "":
if re.match(r'^%$', line):
fp_entry.append(fi.tell())
line = fi.readline()

# Seek to a random entry
try:
fi.seek(random.choice(fp_entry))
except:
sys.exit("Cannot seek.")

# Add the entry to output message and then print it
fortune = ''
line = fi.readline()
while line != '':
if re.match(r'^%$', line):
break
fortune += line
line = fi.readline()
print fortune

# Return fp to beginning of file, close the file, and exit program
fi.seek(0,0)
Code has no effect. I would remove it.
fi.close()
sys.exit()


No need to call sys.exit() here.

My impression is that you are messing with file "pointers" too much which I
would consider rather low-level. For C this is OK as it has no decent
support for strings, but in Python I would suggest to relax and process the
whole file as a string or list of lines.

Here's a different approach that reads fortunes one at a time with a
generator function that collects lines until it encounters a "%\n".
I'm using an algorithm to choose a random fortune that was posted on c.l.py
by Paul Rubin, see
http://mail.python.org/pipermail/pyt...er/201114.html

import random, sys

def fortunes(infile):
""" Yield fortunes as lists of lines """
result = []
for line in infile:
if line == "%\n":
yield result
result = []
else:
result.append(line)
if result:
yield result

def findfortune(filename):
""" Pick a random fortune from a file """
for index, fortune in enumerate(fortunes(file(filename))):
if random.random() < (1.0 / (index+1)):
chosen = fortune

return "".join(chosen)

if __name__ == "__main__":
print findfortune(sys.argv[1]),

As to error handling, I admit I'm lazy, but for small scripts I'm usually
happy with the traceback.

Peter
Jul 18 '05 #4
Or I could see (untested code)
import random, sys

def fortunes (infile):
return infile.read().split ('\n%\n')

def findfortune (filename):
return random.choice (fortunes (file (filename, 'rt'))

if __name__ == '__main__':
print findfortune (sys.argv[1])
Regards. Mel.
Jul 18 '05 #5
Mel Wilson wrote:
Or I could see (untested code)
import random, sys

def fortunes (infile):
return infile.read().split ('\n%\n')

def findfortune (filename):
return random.choice (fortunes (file (filename, 'rt'))

if __name__ == '__main__':
print findfortune (sys.argv[1])


That's what I meant with "in Python I would suggest to relax and process the
whole file as a string or list of lines" in my above post. The point of my
solution is to never have (a) the whole file in memory and (b) to make a
random choice from a set of (initially) unknown size while you go through
it.

Peter

Jul 18 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: Raymond Arthur St. Marie II of III | last post by:
Hi Eric, I've been quietly going around the web asking people to please fix the broken Tuxedo links to your pages as I find them. Hint.-- Hint--...
31
by: poisondart | last post by:
Hi, I'm not sure if this is the right group to post this. If not, then I would appreciate if somebody could point me to the correct group. This is my first time releasing software to the...
5
by: Ivan | last post by:
hi, I saw some program using "request("fieldname") " instead of "request.QueryString" to get the value from URL, what's the different ?? thanks
72
by: B McDonald | last post by:
http://www.galtsvalley.com Hi all. I've recently made some major stylistic changes to my site and now it is essentially a new design with some new CSS plumbing. I am hoping that a few hardy...
1
by: aacool | last post by:
Hi, I've been working on my blogspot blog and have replaced the default available templates with one based on css. I would appreciate tips and advice. I am considering alternate css stylesheets,...
19
by: TC | last post by:
Are there any good sites or forums for a web critique? I went to alt.html.critique and it's pretty dead.
188
by: christopher diggins | last post by:
I have posted a C# critique at http://www.heron-language.com/c-sharp-critique.html. To summarize I bring up the following issues : - unsafe code - attributes - garbage collection -...
39
by: Eric | last post by:
There is a VB.NET critique on the following page: http://www.vb7-critique.741.com/ for those who are interested. Feel free to take a look and share your thoughts. Cheers, Eric. Ps: for those...
23
by: Mark Rae | last post by:
Hi, Because all my public sites are hosted with a 3rd-party ISP and, therefore, I don't have access to their server's EventLog etc, every error is emailed to me. Recently, I've been getting...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.