Newbie question: Any way to improve this code?

  • Thread starter Gustavo Campanelli
  • Start date
G

Gustavo Campanelli

I'm begining to work in a program that cicles through a list of phrases
(basically, a changing signature file). I started yesterday, and I only
have abput 8 full hours of real Python experience.

So far I produced a code that succesfully reads an process the file,
separating the phrases. Is there any way to optimize this code, so that
I don't have to use the if for the first list member?

Now for the data.
The file is firmas.txt, it contains the following three example phrases

Frase 1
Frase 2
Frase 3

Note that this phrases are separated by newline characters. Upon reading
the full file (it won't be long) I get this:

'Frase 1\nFrase 2\nFrase 3\n'

so, as you can see, the newlines are there.

My code is this (I know I should close the file, but so far the runtime
is so small it doesn't really matter, that'll change)

import string
f = open("firmas.txt",'r') # open the file
texto = f.read ()
n = range (len (texto))
frases = [0]
frase =""
cant = 0
for a in n:
if texto [a] != "\n":
frase = frase + (texto [a])
else:
if cant == 0:
frases [0] = frase
else:
frases.append (1)
frases [cant] = frase
cant +=1
frase = ""

Well, that's it, thanks.

Gustavo Campanelli
 
G

Gary Herron

I'm begining to work in a program that cicles through a list of phrases
(basically, a changing signature file). I started yesterday, and I only
have abput 8 full hours of real Python experience.

So far I produced a code that succesfully reads an process the file,
separating the phrases. Is there any way to optimize this code, so that
I don't have to use the if for the first list member?

Now for the data.
The file is firmas.txt, it contains the following three example phrases

Frase 1
Frase 2
Frase 3

Note that this phrases are separated by newline characters. Upon reading
the full file (it won't be long) I get this:

'Frase 1\nFrase 2\nFrase 3\n'

so, as you can see, the newlines are there.

My code is this (I know I should close the file, but so far the runtime
is so small it doesn't really matter, that'll change)

import string
f = open("firmas.txt",'r') # open the file
texto = f.read ()
... bunch of lines deleted ...


Instead of this and all the rest of the code, you can just
frases = f.readlines()

Then 'frases' will be a list of strings, each string containing one line
from the file.

If you want to see what you've got try

print frases

You'll see that each string contains the newline the ended the line in
the file. To get rid of them and any other beginning or ending white
space (if you want) do:

for i in range(len(frases)):
frase = frase.strip()

If your file might contain empty lines, you can get rid of them with
either a standard loop

final = []
for phrase in frases:
if phrase:
final.append(phrase.strip())

Or, if you're adventurous for a beginner, try list comprehensions.

final = [phrase.strip() for phrase in frases if phrase]


And finally, all this could be done in one line

frases = [phrase.strip() for phrase in f.readlines() if phrase]

Gary Herron
 
D

David M. Cook

Gustavo Campanelli wrote: said:
import string
f = open("firmas.txt",'r') # open the file
texto = f.read ()
n = range (len (texto))
frases = [0]
frase =""
cant = 0
for a in n:
if texto [a] != "\n":
frase = frase + (texto [a])
else:
if cant == 0:
frases [0] = frase
else:
frases.append (1)
frases [cant] = frase
cant +=1
frase = ""

f = open("firmas.txt",'r') # open the file
frases = []
for line in f.readlines():
frases.append(line[:-1])

line[:-1] is all but the last element of line.

or even

frases = map(str.rstrip, f.readlines())

although that may strip more of the end than you want.

Dave Cook
 
C

Chris Lee

Gustavo said:
I'm begining to work in a program that cicles through a list of phrases
(basically, a changing signature file). I started yesterday, and I only
have abput 8 full hours of real Python experience.

So far I produced a code that succesfully reads an process the file,
separating the phrases. Is there any way to optimize this code, so that
I don't have to use the if for the first list member?

Now for the data.
The file is firmas.txt, it contains the following three example phrases

Frase 1
Frase 2
Frase 3

Note that this phrases are separated by newline characters. Upon reading
the full file (it won't be long) I get this:

'Frase 1\nFrase 2\nFrase 3\n'

so, as you can see, the newlines are there.

My code is this (I know I should close the file, but so far the runtime
is so small it doesn't really matter, that'll change)

import string
f = open("firmas.txt",'r') # open the file
texto = f.read ()
n = range (len (texto))
frases = [0]
frase =""
cant = 0
for a in n:
if texto [a] != "\n":
frase = frase + (texto [a])
else:
if cant == 0:
frases [0] = frase
else:
frases.append (1)
frases [cant] = frase
cant +=1
frase = ""

Well, that's it, thanks.

Gustavo Campanelli

Ok, so I'm probably talking too soon (...30 minutes of python learning)
but python has a readline() function for the file object.

f = open("firmas.txt",'r') # open the file
texto=f.readline() #texto contains the first line

There is also a readlines() method (note the plural) which reads all of
the lines in a file

f = open("firmas.txt",'r') # open the file
texto=f.readlines() #texto contains an list of all the lines

There is also (I'm learning quickly) the iterator method

f = open("firmas.txt",'r') # open the file
for line in f:
print line #or whatever



....And I spent most of this week thinking the STL was cool.
 
D

Duncan Smith

Gustavo Campanelli said:
I'm begining to work in a program that cicles through a list of phrases
(basically, a changing signature file). I started yesterday, and I only
have abput 8 full hours of real Python experience.

So far I produced a code that succesfully reads an process the file,
separating the phrases. Is there any way to optimize this code, so that
I don't have to use the if for the first list member?

Now for the data.
The file is firmas.txt, it contains the following three example phrases

Frase 1
Frase 2
Frase 3

Note that this phrases are separated by newline characters. Upon reading
the full file (it won't be long) I get this:

'Frase 1\nFrase 2\nFrase 3\n'

so, as you can see, the newlines are there.

My code is this (I know I should close the file, but so far the runtime
is so small it doesn't really matter, that'll change)

import string

the string module doesn't seem to be used
f = open("firmas.txt",'r') # open the file
texto = f.read ()

no need for the space before the parentheses (see
http://www.python.org/peps/pep-0008.html)
n = range (len (texto))
frases = [0]

why not initialise an empty list and append to it?
frase =""
cant = 0
for a in n:
if texto [a] != "\n":
frase = frase + (texto [a])
else:
if cant == 0:
frases [0] = frase
else:
frases.append (1)
frases [cant] = frase

then you can replace the above 5 lines with the following line and remove
all references to 'cant',

frases.append(frase)
cant +=1
frase = ""

Or you could replace the whole thing with,

try:
f = open("firmas.txt",'r')
texto = f.read()
frases = texto.split('\n')[:-1]
finally:
f.close()

Duncan
 
B

Bengt Richter

import string
f = open("firmas.txt",'r') # open the file
texto = f.read ()
n = range (len (texto))
frases = [0]
frase =""
cant = 0
for a in n:
if texto [a] != "\n":
frase = frase + (texto [a])
else:
if cant == 0:
frases [0] = frase
else:
frases.append (1)
frases [cant] = frase
cant +=1
frase = ""

f = open("firmas.txt",'r') # open the file
frases = []
for line in f.readlines():
frases.append(line[:-1])

line[:-1] is all but the last element of line.

or even

frases = map(str.rstrip, f.readlines())

although that may strip more of the end than you want.

Someone's working too hard ;-) Should work:

frases = file('firmas.txt').read().splitlines()

Regards,
Bengt Richter
 
B

Bengt Richter

Or you could replace the whole thing with,

try:
f = open("firmas.txt",'r')
texto = f.read()
frases = texto.split('\n')[:-1]

If you split on something, you don't have to eliminate it,
but you may split off a trailing null string, to satisfy the
logic that you should be able to join the list with the splitter and
get back your original. Splitlines does what you want:
>>> 'abc\ndef\n'.split('\n') ['abc', 'def', '']
>>> 'abc\ndef\n'.splitlines()
['abc', 'def']
>>> 'abc\ndef\n'.split('\n') ['abc', 'def', '']
>>> '\n'.join('abc\ndef\n'.split('\n'))
'abc\ndef\n'

But the result of splitlines gives you the same last line whether it ends with \n or not,
so you can't guarantee reconstruction:
'abc\ndef'

More:
>>> 'abc\ndef\n'.splitlines() ['abc', 'def']
>>> 'abc\ndef'.splitlines() ['abc', 'def']
>>> 'abc\ndef\n\n'.splitlines() ['abc', 'def', '']
>>> '\n'.splitlines() ['']
>>> ''.splitlines() []
>>> 'a'.splitlines()
['a']
finally:
f.close()
I think you forgot (oh, just realized the explanation for my amazement--you're not the other Duncan ;-)
(maybe you didn't forget) that if the open doesn't succeed in the above,
f will not be (re)bound, so f.close() will be problematical either way.

I guess you could fix it (untested) by

try:
f = file("firmas.txt")
try:
frases = f.read().splitlines()
finally:
f.close()
except Exception, e:
print '%s: %s' %( e.__class__.__name__, e)

Regards,
Bengt Richter
 
P

Peter Otten

Duncan said:
try:
f = open("firmas.txt",'r')
texto = f.read()
frases = texto.split('\n')[:-1]
finally:
f.close()

Running this with a nonexistent firmas.txt gives you:

....> python frases.py
Traceback (most recent call last):
File "frases.py", line 6, in ?
f.close()
NameError: name 'f' is not defined

Although it looks less symmetrical, the f = open() should be placed *before*
the try block. When you enter the try block, you are already sure that the
file was opened, and only then it makes sense to ensure that the file will
be closed even if some of the following operations fail.
frases = ... does not need access to the file and thus belongs *after* the
finally block - but that is less crucial.

Another (minor) issue: I'm never confident that a plain text file ends with
a newline character, so in my opinion you risk losing la última frase.

Peter
 
D

Duncan Smith

Bengt Richter said:
[...]
Or you could replace the whole thing with,

try:
f = open("firmas.txt",'r')
texto = f.read()
frases = texto.split('\n')[:-1]

If you split on something, you don't have to eliminate it,
but you may split off a trailing null string, to satisfy the
logic that you should be able to join the list with the splitter and
get back your original. Splitlines does what you want:
'abc\ndef\n'.split('\n') ['abc', 'def', '']
'abc\ndef\n'.splitlines()
['abc', 'def']
'abc\ndef\n'.split('\n') ['abc', 'def', '']
'\n'.join('abc\ndef\n'.split('\n'))
'abc\ndef\n'

But the result of splitlines gives you the same last line whether it ends with \n or not,
so you can't guarantee reconstruction:
'\n'.join('abc\ndef\n'.splitlines())
'abc\ndef'

More:
'abc\ndef\n'.splitlines() ['abc', 'def']
'abc\ndef'.splitlines() ['abc', 'def']
'abc\ndef\n\n'.splitlines() ['abc', 'def', '']
'\n'.splitlines() ['']
''.splitlines() []
'a'.splitlines()
['a']

finally:
f.close()
I think you forgot (oh, just realized the explanation for my
amazement--you're not the other Duncan ;-)
(maybe you didn't forget) that if the open doesn't succeed in the above,
f will not be (re)bound, so f.close() will be problematical either way.

[snip]

Yes, the other Duncan wouldn't have been so sloppy :). Off to check
whether I've done this in any of my 'real' code. And it was the

frases = texto.split('\n')[:-1]

that I was a bit unhappy about (once I'd posted). I feel a bit like a
certain cartoon character, doh. Cheers Bengt.

Duncan
 
S

Scott David Daniels

Gustavo said:
I'm begining to work in a program that cicles through a list of phrases
(basically, a changing signature file). I started yesterday, and I only
have abput 8 full hours of real Python experience.
Too much fun. I wrote a random quote generator. Spec is to to pull
a quote from a quote file at random, with each quote appearing equally
often. I threw in a command line arg to seed the RNG or replace the
quote file name.

Try it yourself before looking below (I'll wait).

import sys, random

def choose_quote(args=None):
"""Choose a quote at random from a quote file.

args should be a list of string arguments. Args begins with '@'
are used to seed the random number generator. Otherwise the
arg is presumed to be the quote file name. If args is passed
in as None, args is grabbed from sys.argv (the command line).
"""

quotefile = SOURCE
best, quote = -1.0, 'Sorry, no quote today. -- the Management'

if args is None:
args = sys.argv[1:]
for arg in args:
if arg.startswith('@'):
random.seed(arg)
else:
quotefile = arg

try:
source = file(quotefile)
except IOError, e:
print >>sys.stderr, 'I cannot seem to read %r.' % quotefile
else:
# The file is open. Choose the line with the highest score.
# Each line is assigned a value by random(), any of which is
# greater than the initial -1. This gives each line in the
# file an equal chance of being chosen.
try:
for line in source:
score = random.random()
if score > best:
best, quote = score, line
except IOError, e:
print >>sys.stderr, 'Error reading file %r.' % quotefile
# Treat any I/O error as EOF. We may already have a quote.
source.close()
return quote.strip()



if __name__ == '__main__':
print choose_quote()


-Scott David Daniels
(e-mail address removed)
 
G

Gustavo Campanelli

Allright, this is just to thank you guys, you helped me dig some methods
I hadn't used, and helped me get some better code, now and for the
future. That's completely priceless. I love this newsgroup :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top