3
\$\begingroup\$

I have a method in a Python app to write a list of records to a CSV file. Each record is a "football player", which is really just a dictionary. But one of the dictionary items contains a list of weekly scores. I want to write out to CSV a record for each player, and then flatten the list of scores and write that out, too.

My code:

def write_csv_file(filename, year, list_of_players):
    print str(datetime.now()) + ' Writing file {0}'.format(OUTPUT_CSV_PATH + filename + '.csv')
    print list_of_players
    with open(OUTPUT_CSV_PATH + filename + '.csv', 'w+') as f:

        writer = csv.writer(f, quotechar='"', quoting=csv.QUOTE_MINIMAL, lineterminator = '\n')

        writer.writerow(['YEAR', 'FILENAME', 'PLAYER_KEY', 'PLAYER_NAME', 'SEASON_TOTAL', 'CALCULATED_SEASON_TOTAL', 'MEAN', 'MEDIAN', 'STD_DEVIATION', 'CV',
            'WK1', 'WK2', 'WK3', 'WK4', 'WK5', 'WK6', 'WK7', 'WK8', 'WK9', 'WK10', 'WK11', 'WK12', 'WK13', 'WK14', 'WK15', 'WK16'])
        for item in list_of_players:
            writer.writerow([year, filename, item['player_key'], item['player_name'], item['season_total'],
                item['calculated_season_total'], item['mean'], item['median'], item['std_deviation'], item['coefficient_of_variation'],
                #item['performance_score'],
                item['scores'][0],
                item['scores'][1],
                item['scores'][2],
                item['scores'][3],
                item['scores'][4],
                item['scores'][5],
                item['scores'][6],
                item['scores'][7],
                item['scores'][8],
                item['scores'][9],
                item['scores'][10],
                item['scores'][11],
                item['scores'][12],
                item['scores'][13],
                item['scores'][14],
                item['scores'][15]
                ])

It's the handling of item['scores'] that I'm sure there's a better way. I tried getting a list comprehension to work but never could get it going.

How can I do this better?

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

One quick win for readability would be to rename item to player. Another improvement would be to put each field on its own line, since the long lines vastly exceed the 79-character limit suggested by PEP 8.

For the 16 scores, you can write…

writer.writerow([
    'YEAR',
    'FILENAME',
    'PLAYER_KEY',
    'PLAYER_NAME',
    'SEASON_TOTAL',
    'CALCULATED_SEASON_TOTAL',
    'MEAN',
    'MEDIAN',
    'STD_DEVIATION',
    'CV'
] + ['WK{0}'.format(i + 1) for i in range(16)])

for player in list_of_players:
    writer.writerow([
        year,
        filename,
        player['player_key'],
        player['player_name'],
        player['season_total'],
        player['calculated_season_total'],
        player['mean'],
        player['median'],
        player['std_deviation'],
        player['coefficient_of_variation']
    ] + player['scores'])
\$\endgroup\$
  • \$\begingroup\$ Perfect! I had to do 'WK{0}'.format(i) instead, but that cleaned it up nice. Also modded to ['WK{0}'.format(i) for i in range(1, len(list_of_players[0]['scores'])+1)]) to ultimately deal with a variable number of weeks as the season progresses. Thanks! \$\endgroup\$ – Peter Tirrell Nov 3 '15 at 4:02
  • \$\begingroup\$ On further thought, I would rewrite the range() because the 17 is unnatural. \$\endgroup\$ – 200_success Nov 3 '15 at 4:47
1
\$\begingroup\$

Use str.format for datetime.now() as well. It will automatically run the str call just by being included. Also you don't need to pass numbers into {}. If you're just using each parameter once, then you can just pass them in order. I'd also recommend creating the filepath in advance of this print call, since you'll need it later anyway.

def write_csv_file(filename, year, list_of_players):
    filepath = OUTPUT_CSV_PATH + filename + '.csv'
    print '{} Writing file {}'.format(datetime.now(), filepath)

Also you should import the os module to create file paths. Specifically, the os.path.join function will create OS appropriate paths from string arguments, which makes it easier to manage path strings.

    filepath = os.path.join(OUTPUT_CSV_PATH, filename + '.csv')

Even just to log a list, you might want to use str.join. You can print a list neater using one of these:

print ', '.join(list_of_players)
print '\n'.join(list_of_players)

str.join will print a long string with each element of a list joined by the string its called on. So the first example above prints all the elements of your list as a comma separated string, while the second separates them with newlines. These are more readable when printed out like this.

Also I don't like the long name list_of_players when just players communicates the same idea. It's clearly multiple players, and since you loop over it people can easily see it's a list, no need to use the name to indicate that.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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