【问题标题】:How to get the number of input arguments of class(__init__)?如何获取类(__init__)的输入参数的数量?
【发布时间】:2021-04-27 16:26:40
【问题描述】:

我想在 python 中获取每个科目的分数并返回其平均值和总和。我知道如果我收到 4 个参数而不是平均分母应该是 4,但是我怎样才能使它成为由输入数量改变的固定代码?,而不仅仅是计数数字和类型 4。我尝试了 Len(self) 或使用 for 循环计数,但 Len 会出错,而且 for 循环也不是那么容易。

class score:
    def __init__(self, language, math, english, science):
        self.language = language
        self.math = math
        self.english = english
        self.science = science
        
    ...

    def sum_scores(self):
        result = self.language + self.math + self.english + self.science
        return result
    
    def average(self):
        average = self.sum_scores()/4 # Here is the problem!
        return average

这是我在堆栈上的第一个问题。很抱歉我糟糕的英语和愚蠢的问题。

【问题讨论】:

  • 是否需要有固定数量的命名参数?或者你可以有可变数量的参数吗?是要求你知道每个分数的主题,还是只知道分数就可以?
  • 我不明白这个问题。由于__init__ 有四个强制 参数(不包括self),所以正确的分母将始终是4
  • @timgeb 面对添加新分数仍然很脆弱,因为除了实际添加新分数之外,您还必须记住更新4(或常量)的使用。
  • @chepner 公平点
  • 哦!所需的代码是因为如果我输入 5 个或更多的输入,那么分母应该会改变。所以我不想每次收到更多输入时都通过输入数字来更改分母!

标签: python class methods


【解决方案1】:

首先不要使用 4 个单独的属性。使用dict 来存储属性;那么就可以查询dict的大小了。

class score:
    def __init__(self, language, math, english, science):
        self.scores = {'language': language, 'math': math, 'english': english, 'science': science}
        
    ...

    def sum_scores(self):
        return sum(self.scores.values())
        
    
    def average(self):
        return self.sum_scores() / len(self.scores)

如果您仍需要每个单独分数的属性,请使用属性:

class score:
    def __init__(self, language, math, english, science):
        self.scores = {'language': language, 'math': math, 'english': english, 'science': science}
        

    @property
    def language(self):
        return self.scores['language']

    # etc.


    def sum_scores(self):
        return sum(self.scores.values())
        
    
    def average(self):
        return self.sum_scores() / len(self.scores)

【讨论】:

  • @고모드 您应该单击答案的绿色复选标记,并找到您认为最有帮助的解决方案。
【解决方案2】:

假设你不知道分数适用的科目是可以的,你可以使用未命名的位置参数

class score:
    def __init__(self, *args):
        self.scores = args
        
    ...

    def sum_scores(self):
        return sum(self.scores)
    
    def average(self):
        return self.sum_scores() / len(self.scores)

【讨论】:

  • 所以你的代码没有将分数应用于科目,只是接收所有分数(无论科目是什么)并计算平均值,对吗?
  • 正确。问题中的代码似乎根本没有使用主题名称,所以我基于主题名称只是占位符的假设制定了这个答案。
【解决方案3】:

对于您的情况,您只需注意数量为 4

但是,您可能希望使用 **kwargs 作为参数(您可以使用任何名称,这只是约定;** 将所有未明确命名的关键字 args 分配给 dict)

SUBJECTS = ("math", "science" ... )

class MyClass():
    def __init__(self, **kwargs):  # also consider *args
        self.subjects = {k: v for k, v in kwargs.items() if k in SUBJECTS}

    def sum_scores(self):
        return sum(self.subjects.values())
    
    def average(self):
        return self.sum_scores() / len(self.subjects)
>>> c = MyClass(math=10, science=8)
>>> c.sum_scores()
18
>>> c.average()
9.0

您可能还需要考虑报告用于帮助用户发现使用错误的参数

【讨论】:

  • 您的代码提倡全局对象和类之间的紧密耦合。将全局 subjects 设为类属性可能会更好。
  • 这很公平 - 不过这里是 fastest gun in the west!我认为一个很好的权衡是大写的、不可变的全局;当混合继承时,类属性可能很难推理(尽管显然有好处!)
【解决方案4】:

您可以在 init 函数中使用关键字参数:

class Score:
     def __init__(self, **scores):
         self.classes = []
         for _class, score in scores.items():
             setattr(self, _class, score) # self.english, self.math, etc.
             self.classes.append(_class) # ["math", "english"]
     def sum_scores(self):
         sum = 0
         for i in self.classes:
              sum += getattr(self, i)
         return sum
     def average(self):
         return self.sum_scores() / len(self.classes)

通过使用 **scores,您可以动态迭代作为字典传递给函数的所有参数。这里我使用setattr函数给Score对象一个类名的属性,它的值就是字典中对应的值。这样,我可以动态迭代每个类,无论是提供 3 个还是 100 个类作为输入。

score1 = Score(math=67, english=98, art=76)

print(score1.sum_scores())
print(score1.average())
>>> 241
>>> 80.3333333333

【讨论】:

  • 我印象深刻!!您的代码不需要指定所有方法,例如“def math..(self)”。 'setattr' 和 'getattr' 是非常强大的工具,我认为!我真的很关心如何返回我收到的每个科目的分数,它解决了我的两个问题!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-24
  • 2021-08-17
  • 2012-05-24
  • 2021-04-08
  • 2020-06-18
  • 1970-01-01
相关资源
最近更新 更多