2013-01-04 178 views
0

如何将3个数据(在相邻列中)的名称的CSV文件转换为创建的类的变量,数据作为参数?CSV列表(行,列)到Python变量名称(名称,值)

下面的代码似乎创建的对象,但列表是对象的位置,而不是我喜欢的名称。

任何人都可以帮忙吗?

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") 

首先print语句打印:

North Carolina 

print语句打印:

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

有什么理由不使用Python的CSV模块? –

+0

@HaraldScheirich:在这种情况下,它不是绝对必需的,因为它是一个相当简单的CSV。但是,更好地使用图书馆。 – hayavuk

+0

我不完全清楚你想要“打印Teamlist”来打印。你想要一个以逗号分隔的所有团队名称列表,或者每个团队的一个以换行符分隔的列表(以逗号分隔的所有团队属性列表),还是......?如果我在我的回答中猜测错误,请明确说明您的预期输出是什么。 – abarnert

回答

1

对象位置对象的方式打印出来。严格来说,在list上调用strrepr对列表上的每个元素调用repr。默认情况下,对象Teams上的repr(team)将返回类似<main.Teams object at 0x02953230>的内容。您可以通过在Teams类上定义__repr__方法来覆盖该方法。但是,这听起来不像你想要的。

如果TeamListTeams对象的列表,并希望把它变成自己的TeamName成员的名单,你只需用list comprehension,将其转换:

TeamNameList = [team.TeamName for team in TeamList] 

注意,这还不是将成为正是你要打印出来:

你可能想是这样的:

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

从您的评论:

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

我想我明白你想要的这里。你希望能够模拟北卡罗来纳州和南卡罗来纳州之间的比赛,当你拥有的是TeamList

要做到这一点,你可能想创建一个dict,名称映射到Teams的物体,就像这样:

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

现在,你可以做这样的事情:

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

现在,simGame将获得Teams类的北卡罗莱纳州和南卡罗来纳州的实例作为其参数teamAteamB,因此它可以执行以下操作:

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) 

这就是你想要的吗?

一些补充意见:

你也可以做同样的事情,使用map列表理解,这避免了写team两次,但它也意味着你不能正常使用表达式语法:

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

或者你可以同时使用maplambda找回表达式语法回来......和team重复:

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

但对于这样的情况,列表理解通常被认为是pythonic的方式来做到这一点。 (另外,它不一样,如果你去到Python 3的变化,而从list到一个迭代器,这意味着print TeamNameList会给你像<builtins.map at 0x108022350>map变化......但是', '.join(TeamNameList)仍然可以工作。)

作为一个侧面说明,在标准(PEP 8)Python风格中,通常只有类是这样在TitleCase中的,而变量和属性是在lower_case中。如果你真的很喜欢CamelCase,那么你可以用lowerFirstCamelCase避开它,但是使用TitleCase会让人们阅读你的代码,他们会立即尝试找出TeamName类的定义。另请参阅bvukelic的评论。

至于另一个方面说明,你似乎是做了很多重复的代码,我不知道为什么:

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

你只是复制infonewTeam;为什么添加所有那些永不再使用的中间变量?

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

你可以只用更换了这一切:

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

甚至:

newTeam2 = Teams(*info) 

如果你有需要对不同的变量的地方,你还没有告诉我们,那很好,但你仍然不可能需要newTeam;只是这样做:

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

说到PEP8(也是根据不同语言的共同协议),应用程序名称也不应该用于常量以外的其他任何内容。 – hayavuk

+0

@bvukelic:好点。使用两个字母的缩写名称(当然应该谨慎地使用它们,当然......),把'FT'当作缩写CamelCase而不是ALL_CAPS似乎不太合理......但是,我仍然不会命名任何'FT',即使我能找到一种合理化它的方法。 – abarnert

+0

@abarnet:甚至不会用类来做到这一点。 :)如果太短,我总是会展开。此外,使用稍长的名称可以生成自编码代码,这是一件好事。 – hayavuk

0

只是为了掩饰这个问题的另一种解释:

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__() 

当你打印对象时,它会显示为TeamName

+0

确实如此,但是当你打印对象的“列表”时,如同OP所做的那样,这将无济于事 - 正如我在我的回答中所解释的,“列表”中的'str'或'repr'调用' repr'上的元素,而不是'str'。而'unicode'也是如此 - 但有一个额外的问题,即使'print team'也不会调用'unicode';它调用'str'。所以如果你在某个地方显式地使用“unicode(team)”,这只会起作用。 – abarnert

+0

另外,现在我想到了,你从'__unicode__'返回一个'str',这很容易让人误解。 – abarnert

+0

@abarnert:你说得对。我会纠正这些。 – hayavuk

1

我会使用csv模块做这样的事情,主要是基于module documentation中的例子。可能需要调整,这只是我的头顶,但我总是在使用这些类型的文件时使用相关的东西。

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) 
+0

有趣!我想我会采取这个想法,并将其与Dict的想法结合起来,看看我能否得到一些优雅的代码。 –

+0

+1。不是OP的问题的直接答案,但它可能有助于使他的代码更易读,更易于维护。 – abarnert

0

类的实例是如何被显示的是给他们定制__str__()和/或__repr__()转换方法来控制。以下是您的代码可以写入的一种方式,也可以遵循PEP 8 Style Guide中的许多建议。正如其他人已经建议的那样,使用csv模块来读取文件,您也可以进一步改进或简化它,但我将主要关注您问题中显示的代码。

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") 

输出示例:

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