Daniel McIntosh
Daniel McIntosh

Reputation: 17

CSV list (row, column) to Python list of Variables (name, value)

How can I convert a CSV file of names with 3 pieces of data (in adjacent columns) into variables of a created class that takes the adjacent pieces of data as arguments?

The code below appears to create the objects but the list is of object locations and not the names as I would prefer.

Can anyone help?

class Teams(object):
  def __init__(self, TeamName, FT, FG, Three):
    self.TeamName = TeamName
    self.FT = FT
    self.FG = FG
    self.Three = Three

North_Carolina = Teams("North Carolina", .643,.458,.371)

print North_Carolina.TeamName, North_Carolina.FT, North_Carolina.FG,North_Carolina.Three
## works fine but manually typed data

def getData(fname):  ##fname is a csv file with 4 columns and 348 rows. One header row.
    Data = open(fname, 'r')
    TeamList = []
    #print Data.read() ## prints a list with comma separated values and line return
    for line in Data:
      info = line.split(",") ##info is a list of lists of Data with Team,FT,FG,3P
      name = info[0]
      FT = info[1]
      FG = info[2]
      Three = info[3]
      newTeam = (name, FT, FG, Three)
      newTeam2 = Teams(newTeam[0],newTeam[1],newTeam[2],newTeam[3]) ##newTeam2 is an object. 
      TeamList.append(newTeam2)
    print TeamList[1].TeamName ##prints North Carolina list[0] print header
    print TeamList #prints list of object locations but not objects themselves

getData("Stats 01-04-2013.csv")

First print statement prints:

North Carolina

Second print statement prints:

[<__main__.Teams object at 0x02953230>, <__main__.Teams object at 0x029532B0>, etc etc

Upvotes: 0

Views: 2387

Answers (4)

martineau
martineau

Reputation: 123423

How class instances get displayed is controlled by giving them custom __str__() and/or __repr__() conversion methods. Here's one way your code could be written to do that and also make it follow many of the recommendations in the PEP 8 Style Guide. You may also be able improve or simplify it even more by using the csv module to read the file, as already suggested by others, but I'll focus mostly on the code shown in your question.

class Team(object):
    def __init__(self, team_name, free_throws, field_goals, three_pointers):
        self.team_name = team_name
        self.free_throws = free_throws
        self.field_goals = field_goals
        self.three_pointers = three_pointers

    def __repr__(self):
        return '{}({!r}, {}, {}, {})'.format(self.__class__.__name__,
                                             self.team_name, self.free_throws,
                                             self.field_goals, self.three_pointers)

def get_data(fname):  # fname is a csv file with 4 columns and one header row
    teams = []
    with open(fname, 'rt') as csv_file:
        csv_file.next()  # skip header row
        for line in csv_file:
            info = line.strip().split(",")
            teams.append(Team(*info))  # create a Team instance and add it to list
    return teams

print get_data("Stats 01-04-2013.csv")

Sample output:

[Team('North Carolina',  .643,  .458,  .371), Team('Michigan',  .543,  .358,  .271)]

Upvotes: 0

abarnert
abarnert

Reputation: 365657

The object locations are how the objects are printed out. Strictly speaking, calling str or repr on a list calls repr on each element on the list. By default, repr(team) on a Teams object will return something like <main.Teams object at 0x02953230>. You can override that by defining a __repr__ method on the Teams class. However, this doesn't sound like what you want here.

If TeamList is a list of Teams objects, and you want to turn it into a list of their TeamName members, you just use a list comprehension to convert it:

TeamNameList = [team.TeamName for team in TeamList]

Note that this still isn't going to be exactly you want to print out:

>>> print TeamNameList
['North Carolina', 'South Carolina', 'West Carolina', 'East Carolina', 'Underground Carolina', 'Cloud-level Carolina', 'Past Carolina', 'Future Carolina'] # those are all states, right?

You probably want something like this:

>>> print ', '.join(TeamNameList)
North Carolina, South Carolina, West Carolina, East Carolina, Underground Carolina, Cloud-level Carolina, Past Carolina, Future Carolina

From your comments:

there is a later function simGame(teamA, Teamb)

I see the instances, however I am not sure how to call them in the second function. I had planned on calling them by name. In the example I gave, North_carolina can be passed to the later (not shown function) and calculations can be run on the data

I think I understand what you want here. You want to be able to simulate a game between North Carolina and South Carolina, when all you have is the TeamList.

To do that, you probably want to create a dict, mapping the names to the Teams objects, like this:

TeamDict = {team.TeamName: team for team in TeamList}

Now, you can do things like this:

simGame(TeamDict['North Carolina'], TeamDict['South Carolina'])

Now, simGame is going to get the North Carolina and South Carolina instances of the Teams class as its teamA and teamB arguments, so it can do things like:

def simGame(teamA, teamB):
    scoreA = int(teamA.FT * 1 * 20) + int(teamA.FG * 2 * 40) + int(teamA.Three * 3 * 10)
    scoreB = int(teamB.FT * 1 * 20) + int(teamB.FG * 2 * 40) + int(teamB.Three * 3 * 10)
    if scoreA > scoreB:
        print 'Home team {} beats visitor {} by {}!'.format(teamA.TeamName,
                                                            teamB.TeamName,
                                                            scoreA - scoreB)
    else:
        print 'Visitors {} win by {} over {} at home!'.format(teamB.TeamName,
                                                              scoreB - scoreA,
                                                              teamA.TeamName)

Is that what you want?

Some additional comments:

You can also do the same thing as the list comprehension using map, which avoids having to write team twice, but it also means you can't use normal expression syntax:

TeamNameList = map(operator.attrgetter('TeamName'), TeamList)

Or you can use map together with lambda to get back the expression syntax back… and the repeat of team:

TeamNameList = map(lambda team: team.teamName, TeamList)

But for cases like this, the list comprehension is generally considered the pythonic way to do it. (Also, it doesn't change if you go to Python 3, whereas map changes from a list to an iterator, which means print TeamNameList will give you something like <builtins.map at 0x108022350>… But ', '.join(TeamNameList) will still work.)

As a side note, in standard (PEP 8) Python style, usually only classes are in TitleCase like this, and variables and attributes are in lower_case. If you really like CamelCase, you can get away with lowerFirstCamelCase, but using TitleCase will throw off people reading your code, who will immediately try to figure out where the TeamName class is defined. Also see the comments from bvukelic.

As another side note, you seem to be doing a lot of repeated code, and I'm not sure why:

  name = info[0]
  FT = info[1]
  FG = info[2]
  Three = info[3]
  newTeam = (name, FT, FG, Three)

You're just copying info to newTeam; why add all those intermediate variables that never get used again?

  newTeam2 = Teams(newTeam[0],newTeam[1],newTeam[2],newTeam[3])

You could replace all of that with just:

  newTeam2 = Teams(info[0],info[1],newTeam[2],newTeam[3])

Or even:

  newTeam2 = Teams(*info)

If you have a need for the separate variables somewhere that you haven't shown us, that's fine, but you still can't possibly need newTeam; just do this:

  newTeam2 = Teams(name, FT, FG, Three)

Upvotes: 0

Kyle Maxwell
Kyle Maxwell

Reputation: 627

I'd use the csv module to do something like this, largely based on the examples in the module documentation. Tweaks may be needed, this is just off the top of my head, but I always use the relevant when working with these types of files.

import csv

with open('teams.csv', 'rb') as csvfile:
    teamreader = csv.reader(csvfile)
    for row in teamreader:
        newTeam = Teams(row[0], row[1], row[2], row[3])
        teamList.append(newTeam)

Upvotes: 1

user234932
user234932

Reputation:

Just to cover another interpretation of the question:

class Teams(object):
    def __init__(self, TeamName, FT, FG, Three):
        self.TeamName = TeamName
        self.FT = FT
        self.FG = FG
        self.Three = Three

    def __str__(self):
        return str(self.TeamName)

    def __repr__(self):
        return self.__unicode__()

Whenever you print the object, it will be shown as TeamName

Upvotes: 0

Related Questions