3
\$\begingroup\$

This reads a list of points from a file with a certain format:

<number of points>
x1 y1
x2 y2

How I can make it better?

from collections import namedtuple
Point = namedtuple('Point ', ['x', 'y'])
def read():
    ins = open("PATH_TO_FILE", "r")
    array = []
    first = True
    expected_length = 0
    for line in ins:
        if first:
            expected_length = int(line.rstrip('\n'))
            first = False
        else:
            parsed = line.rstrip('\n').split ()
            array.append(Point(int(parsed[0]), int(parsed[1])))
    if expected_length != len(array):
        raise NameError("error on read")
    return  array
\$\endgroup\$
2
  • \$\begingroup\$ If you're dealing with points you might want to use a library like Shapely, which will give you a nice Point object. \$\endgroup\$
    – monkut
    Commented Dec 14, 2012 at 3:25
  • \$\begingroup\$ @monkut, thx I'll see. \$\endgroup\$ Commented Dec 14, 2012 at 9:46

3 Answers 3

4
\$\begingroup\$

Another improvement is to use open as a context manager so that you don't have to remember to .close() the file object even if there are errors while reading.

def read():
    with open("FILE", "r") as f:
        array = []
        expected_length = int(f.next())
        for line in f:
            parsed = map(int, line.split())
            array.append(Point(*parsed))
        if expected_length != len(array):
            raise NameError('error on read')
        return array

See http://docs.python.org/2/library/stdtypes.html#file.close for more details.

\$\endgroup\$
0
3
\$\begingroup\$

You don't need all that expected_length and first=True stuff. You can treat a file as an iterator, and it will return objects until it quits, so you can just use the .next() method and throw item away, or save it to a variable if you wish. In that sense, it's best to write two functions-- one to deal with the file, and another to deal with a single line as provided by the file object.

def lineparse(line):
    ''' Parses a single line. '''
    # your code goes here

def fileparse(filepath):
    f = open(filepath, "r")
    n = int(f.next()) # this also advances your iterator by one line
    while True: 
        yield lineparse(f.next())
    f.close()

data = list(fileparse(filepath))
\$\endgroup\$
2
  • \$\begingroup\$ expected_length is a check that the supposed length of the array equals the amount of data, you can't just ignore it. \$\endgroup\$
    – Stuart
    Commented Dec 14, 2012 at 3:54
  • \$\begingroup\$ Ah ignore me, I've just noticed you use n = to get the expected length. Still a bit confusing that you say you don't need expected_length though. \$\endgroup\$
    – Stuart
    Commented Dec 14, 2012 at 4:08
3
\$\begingroup\$

Not that big a change but you don't need to worry about stripping out \ns as the split and int functions will take care of that. Secondly, as already pointed out, you can grab the first line by just calling .next() then use a loop for the remaining lines.

def read():
    ins = open("FILE", "r")
    array = []
    expected_length = int(ins.next())
    for line in ins:
        parsed = line.split()
        array.append(Point(int(parsed[0]), int(parsed[1])))
    if expected_length != len(array):
        raise NameError('error on read')
    ins.close()
    return array
\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.