Python - 如何从自定义 objects 列表中提取属性并将其转换为浮点数?

Python - How to pull an attribute out of list of custom objects and convert it to a float?

我是新手 Python 用户,所以我希望我没有错过一些基本的东西,但我觉得我已经尽了自己的努力来尝试自己研究这个问题,所以这里开始。

简而言之,我正在编写一个程序,该程序将分析体育统计数据并最终根据所选统计数据为每支球队的实力生成评级。

我可以成功读取简单的 csv 文件,我对我创建的自定义 object class 相当满意,该自定义将统计数据存储为每个团队的属性,但我 运行当我去计算评级时遇到了一个问题。本质上,我需要根据我感兴趣的每个统计数据对所有团队进行排序,根据该统计数据对团队进行排名,并为每个团队的排名分配一个分值。这将根据每个统计数据的排名产生一个累积评分。但是,我在将统计值作为浮点数获取时遇到了一些问题,我认为我需要这样做才能正确排序。

这是我试过的代码:

我创建了一个团队 object,如下所示。为了便于阅读,此版本删除了大部分属性,但其他属性都非常相似。

    class team(object):
        def__init__(self,teamName="",passOffYc=0, passOffAya=0):
            self.teamName = teamName
            self.passOffYc = passOffYc
            self.passOffAya = passOffAya
            self.score = 0

这些 object 是从一个 csv 文件构建的,该文件具有 header 和统计类别,每一行代表一个团队及其统计数据。我正在使用 csv.DictReader 读取文件,如下所示:

    league= []

    with open(passoffense) as csvfile:
        statreader = csv.DictReader(csvfile, delimiter=',')
        for row in statreader:     
            newTeam = team(row["Tm"],row["Y/C"],row["AY/A"])
            print(newTeam, "added")
            league.append(newTeam)

此时我想我有一个名为 league 的列表,其中包含 csv 文件中每一行的团队 object 并且团队名称、passOffYc 和 passOffAya 属性已采用行元素 Tm 的值、Y/C 和 AY/A。这些是团队名称、每次接球码数和每次尝试平均码数,因此后两个都是小数。

为了尝试为每支球队创建得分 object,我想先通过 passOffYc 对联赛列表进行排序,确定每支球队的排名,然后为所有球队重复 passOffAya 等等完整版程序中的属性。

为了理解 attrgetter 或 lambda 函数,我尝试了两种不同的实现方式。

我的 attrgetter 想法是这样的:

    sortedTeams = sorted(league, key = attrgetter("passOffYc"))

我的理解是,这会根据属性 passOffYc 对名为 league 的列表进行排序,但我遇到的问题是排序没有产生预期的输出。

如果 passOffYc 为 19、23、14、7 和 9,我希望排序结果为 7、9、14、19、23。但是最终排序为 14、19、23, 7、9。我的研究让我相信这是因为值是字符串而不是整数(或者更准确地说是浮点数,因为某些值有小数)不太确定如何解决这个问题我试过:

    sortedTeams = sorted(league, key = float(attrgetter("passOffYc"))

但这给了我错误:

    TypeError: float() argument must be a string or a number, not 'operator.attrgetter'

所以显然它不是一个字符串,而是一个 operator.attrgetter object。我一直无法弄清楚如何将排序函数的键获取到 float 类型,所以我也尝试使用我在搜索时读到的 lambda 函数:

    sortedTeams = sorted(league, key = lambda team: float(team.passOffYc))

这似乎非常接近我希望发生的事情,因为它排序正确,但后来我 运行 遇到了缩放问题。由于在我的程序的完整版本中有 20 多个属性需要排序,因此我想避免需要键入上述语句 20 次来适应每个属性。

我想尝试定义一个函数,使其达到以下效果:

    def score(stat):
        sortedTeams = sorted(league, key = lambda team: float(team.stat))

我认为这将允许我传递到 lambda 函数,我想根据哪个统计数据进行排序,但随后我收到错误:

    AttributeError: 'team' object has no attribute 'stat'

我认为这是因为可能无法将参数传递给 lambda 函数,或者我不理解某些东西,因为我也尝试过:

    sortedTeams = sorted(league, key = lambda team, stat=stat: float(team.stat))

这导致了同样的错误。哇!如果你还在读这篇文章,谢谢你阅读我的文章。有什么想法可以解决这个问题吗?

一旦我使排序正常工作并可以对其进行缩放,我打算枚举排序列表以获得排名,并且我开始考虑解决关系的策略。再次感谢您的帮助!

您只需创建带有浮动内容的原始团队条目:

newTeam = team(row["Tm"],float(row["Y/C"]),float(row["AY/A"]))

如果您想采用 lambda 方法,您可以使用:

sortedTeams = sorted(league, key = lambda team: float(attrgetter("passOffYc")(team)))

这可以类似地用在您的函数评分函数中。您缺少的是 attrgetter returns 一个函数。然后,您可以通过向它传递一个参数(在本例中为团队)来调用该函数。然后可以将该结果传递给 float。在那个函数中你可以使用:

lambda team: float(attrgetter(stat)(team))

据我了解,您希望将所需字段的字符串名称传递给函数。如果那是对的,那么代替:

def score(stat):
    sortedTeams = sorted(league, key = lambda team: float(team.stat))

试试这个:

def score(stat):
    sortedTeams = sorted(league, key = lambda team: float(getattr(team, stat)))

一些解释。 team.stat - 访问对象 team 的名称为 "stat" 的属性。 getattr(team, stat) - 访问对象 team.

stat 变量中给定名称的属性