我需要为一个项目制作一个排行榜。必须有3个文件,2个文件由1个类组成,最后一个文件用于运行程序。我已经完成了所有的部分,但是当我调用一个方法来添加一个团队时,程序会添加名称,但它不会将它插入到团队列表中(应该这样做)。当我尝试在列表中显示项目时,程序会显示一条错误消息,而不是显示实际的团队。
我该如何解决?任何帮助将不胜感激。:)
我需要为一个项目制作一个排行榜。必须有3个文件,2个文件由1个类组成,最后一个文件用于运行程序。我已经完成了所有的部分,但是当我调用一个方法来添加一个团队时,程序会添加名称,但它不会将它插入到团队列表中(应该这样做)。当我尝试在列表中显示项目时,程序会显示一条错误消息,而不是显示实际的团队。
我该如何解决?任何帮助将不胜感激。:)
这里有几件事:
当我尝试显示列表中的项目时,程序显示:team.Team object at 0x000000000332A978 insted 显示实际团队。
用户类的默认显示类似于<team.Team object at 0x000000000332A978>
. 如果你想让它显示不同的东西,你必须告诉 Python 你想显示什么。为此有两个单独的功能:__repr__
和__str__
。这个想法是第一个是程序员的表示,第二个是用户的表示。如果您不需要两种不同的表示形式,只需定义__repr__
它,它就会在需要时使用它__str__
。
因此,解决此问题的一个非常简单的方法是将其添加到Team
类中:
def __repr__(self):
return 'Team("{}")'.format(self._name)
现在,如果您调用league.addTeam('Dodgers')
, then print(l._table)
,您将[Team("Dodgers")]
得到[<team.Team object at 0x000000000332A978>]
.
同时,这两种方法可能不是您想要的:
def removeTeam(self,team):
self._table.remove(team)
def returnPosition(self,team):
return self._table.index(team)
这些将删除或查找给定Team
对象的团队——不是名称,甚至是Team
根据名称创建的新对象,而是对存储在_table
. 这并不是那么有用,而且您似乎只想用名字来称呼它们。
有两种方法可以解决此问题:您可以Team
通过将此方法添加到类中进行更改,以便按名称而不是按对象身份进行比较:
def __eq__(self, other):
return self._name == other._name
这意味着如果你说Team('Giants') == Team('Giants')
,它现在将是 true 而不是 False。即使第一支球队在不同的联赛中,并且拥有不同的 WL 记录,等等(例如,就像来自旧金山的棒球“巨人队”与来自纽约的足球“巨人队”),就 Python 而言担心,他们现在是同一个团队。当然,如果这不是您想要的,您可以编写任何其他__eq__
看起来更合适的函数。
无论如何,如果你这样做,index
andremove
函数现在将能够找到任何Team
同名的,而不是完全相同的团队,所以:
def removeTeam(self,team_name):
self._table.remove(Team(team_name))
def returnPosition(self,team_name):
return self._table.index(Team(team_name))
如果您采用这种方式,您可能需要考虑定义所有比较方法,例如,您可以对团队列表进行排序,然后按名称排序。
或者您可以更改这些方法,使它们不能基于相等性工作,例如,通过像这样重新定义它们:
def removeTeam(self,team_name):
self._table = [team for team in self._table if team._name != team_name]
def returnPosition(self,team_name):
return [team._name for team in self._table].index(team_name)
要了解这些是如何工作的,如果您不习惯阅读列表推导,请将每个推导转换回等效循环:
self._table = [team for team in self._table if team._name != team_name]
temp = []
for team in self._table:
if team._name != team_name:
temp.append(team)
self._table = temp
如果您逐步执行此操作,temp
最终会得到表格中每个团队的列表,除了您要删除的团队,然后您将旧的替换为self._table
过滤后的新团队。filter
(如果你知道这个函数,另一种写相同想法的方法是用。)
创建一个新的过滤列表通常比就地修改列表更好。有时出于性能原因不这样做,有时它最终会变得非常复杂且难以理解,但推理起来通常更快更简单。此外,就地修改列表会导致以下问题:
for i, value in enumerate(mylist):
if value == value_to_remove:
del mylist[i]
玩一会儿,你会发现它实际上不起作用。理解为什么有点复杂,你可能不想等到以后再学习。解决问题的常用技巧是遍历列表的副本……但是一旦你这样做了,你现在就同时遇到了最糟糕的过滤和最糟糕的就地删除。
第二个函数可能有点太聪明了,但我们看一下:
def returnPosition(self,team_name):
return [team._name for team in self._table].index(team_name)
首先,我正在创建一个与原始列表类似的列表,但它只是名称而不是团队对象的列表。同样,让我们分解列表推导:
temp = []
for team in self._table:
temp.append(team._name)
或者试着翻译成英文:这是表格中每支球队的球队名称列表。
现在,因为这是一个团队名称列表,我可以使用index(team_name)
它,它会找到它。而且,因为这两个列表具有相同的形状,我知道这也是在原始team
列表中使用的正确索引。
一个更简单的解决方案是_tables
从 a list
of Team
s更改为dict
到 s 的映射名称Team
。这可能是最 Pythonic 的解决方案——它看起来比编写列表推导式来执行简单的操作要简单得多。(这也可能是最有效的,但除非你有一些真正巨大的联赛,否则这几乎无关紧要。)然后你甚至不需要returnPosition
任何东西。要做到这一点:
def __init__(self):
self._table={}
def addTeam(self,name):
self._table[name]=Team(name)
def removeTeam(self,team_name):
del self._table[team_name]
def returnPosition(self,team_name):
return team_name
def updateLeague(self,team1_name1,team_name2,score1,score2):
if score1>score2:
self._table[team_name1].win()
self._table[team_name2].loss()
elif score1==score2:
self._table[team_name1].draw()
self._table[team_name2].draw()
elif score1<score2:
self._table[team_name1].loss()
self._table[team_name2].win()
请注意,我已定义returnPosition
将团队名称本身作为职位返回。如果您考虑一下,dict
键的使用方式与索引完全相同list
,因此这意味着有人为所需的“旧”API 编写的任何代码returnPosition
仍可与“新”API 一起使用。(我可能不会尝试将它卖给分配了需要我们使用的问题的老师returnPosition
,但是对于我想让我的 1.3 用户更容易迁移到 2.0 的真实图书馆,我可能会。 )
这只需要一些其他的更改。在displayList
andsaveList
中,您迭代self._table.values()
而不是self._table
; 中loadList
,您更改self._table.append(team)
为self._table[a] = team
。说到loadList
:您可能需要考虑将这些局部变量从a
、b
、c
和重命名d
为name
、wins
、losses
和draws
。
其他一些评论:
name
、wins
、losses
等的成员,然后直接访问它们。(如果有人告诉你这是不好的风格,因为它不允许你在不改变接口的情况下替换实现,那么这只适用于 Java 和 C++,而不是 Python。如果你需要替换实现,只需继续阅读@property
。)print("""""")
——而且很容易不小心误算"
字符数。(特别是因为某些 IDE 实际上会对此感到困惑,并认为多行字符串永远不会结束。)只需print()
.while
在循环 ( while x!="q":
) 和内部循环中都有相同的结束条件break
。这两个地方都不需要它。要么将其更改为while True:
,要么摆脱break
(只需 make options("q")
do print("Goodbye")
,因此您根本不需要在循环内对其进行特殊处理)。elif
语句时,想想你是否可以把它变成一个dict
短函数。我不确定在这种情况下这是一个好主意,但总是值得考虑并做出明确的决定。最后一个想法看起来像这样:
def addTeam():
name=input("Enter the name of the team:")
l.addTeam(name)
def removeTeam():
teamToRemove=input("Enter the name of the team you want to remove:")
l.removeTeam(teamToRemove)
def recordGame():
team1=input("What is the name of the team?")
ans1=int(input("Enter the number of goals for the first team:"))
team2=input("What is the name of the team?")
ans2=int(input("Enter the number of goals for the second time:"))
l.updateLeague(team1,team2,ans1,ans2)
optionsdict = {
"a": addTeam,
"d": l.displayList,
"s": l.saveList,
"l": l.loadList,
"r": removeTeam,
"rec": recordGame,
}
def options(x):
func = optionsdict.get(x)
if func:
func()
正如我所说,我不确定在这种情况下它实际上是否更清楚,但值得考虑。