1

我需要为一个项目制作一个排行榜。必须有3个文件,2个文件由1个类组成,最后一个文件用于运行程序。我已经完成了所有的部分,但是当我调用一个方法来添加一个团队时,程序会添加名称,但它不会将它插入到团队列表中(应该这样做)。当我尝试在列表中显示项目时,程序会显示一条错误消息,而不是显示实际的团队。

我该如何解决?任何帮助将不胜感激。:)

4

1 回答 1

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__看起来更合适的函数。

无论如何,如果你这样做,indexandremove函数现在将能够找到任何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 listof Teams更改为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 的真实图书馆,我可能会。 )

这只需要一些其他的更改。在displayListandsaveList中,您迭代self._table.values()而不是self._table; 中loadList,您更改self._table.append(team)self._table[a] = team。说到loadList:您可能需要考虑将这些局部变量从abc和重命名dnamewinslossesdraws

其他一些评论:

  • 正如 kreativitea 在评论中所说,您不应创建“私有”变量,然后在 Python 中添加无操作访问器方法。它只是隐藏了真实代码的更多样板,而且还有一件你可能会因为愚蠢的错字而出错的事情,你有一天会花费数小时进行调试。只需拥有名为namewinslosses等的成员,然后直接访问它们。(如果有人告诉你这是不好的风格,因为它不允许你在不改变接口的情况下替换实现,那么这只适用于 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()

正如我所说,我不确定在这种情况下它实际上是否更清楚,但值得考虑。

于 2012-12-06T19:28:09.767 回答