为什么我在第二次运行类方法时收到 TypeError?

Why am I getting a TypeError the second time I run a class method?

提问人:Ryan R. McKnight 提问时间:8/4/2023 最后编辑:Scott HunterRyan R. McKnight 更新时间:8/4/2023 访问量:32

问:

Python 和一般编程新手。目前正在学习类和对象,真的很挣扎。在这个特定示例中,我有一个 Animal 父类和一个 EggLayers 子类。EggLayers 类有一个方法来计算特定实例一周的鸡蛋产量,然后将该值追加到列表中。我有另一种方法可以计算鸡的终生产量。这个想法是,每周的总数从运行第一个方法开始进入一个列表,然后第二个方法对列表求和以返回实例的生存期总数。第一次运行良好,但是,当我第二次尝试运行第一个方法时,我得到一个 TypeError('int' 对象不可调用)。

我在代码中的各个地方尝试了 int()。也不要以为我在任何地方覆盖了 int() 函数。显然,这是导致此错误的两个最常见原因。如果我遇到上述任何一个问题,我认为它不会第一次运行。

class EggLayers(Animal):
    """A class for egg laying animals"""
    type = "chicken"

    def __init__(self, name, age, color, tag):
        super().__init__(name, age, color, tag)

    def eggs_week(self):    # to calculate eggs/week and then append to list
        self.eggs_list = []
        self.eggs_day = int(input("Eggs today?  "))
        self.eggs_day = self.eggs_day
        self.eggs_week = self.eggs_day * 7
        self.eggs_list.append(self.eggs_week)
        print(f"{self.name} laid {self.eggs_week} this week")
        return self.eggs_week

    def eggs_lifetime(self):  # to sum the values in the list above
        self.eggs_lifetime = sum(self.eggs_list)
        print(f"Liftetime production for {self.name} is {self.eggs_lifetime}")
        return self.eggs_lifetime

chicken1 = EggLayers('chicken1', 3, 'white', '002')

chicken1.eggs_week()
chicken1.eggs_lifetime()
chicken1.eggs_week() # Only throws an error the second time

Python 函数 方法

评论

1赞 chepner 8/4/2023
首次调用时,将创建一个隐藏 class 属性的实例属性。大多数实例属性看起来应该只是局部变量,不需要在对方法的给定调用中幸存下来。EggLayers.eggs_week
0赞 chepner 8/4/2023
(出于同样的原因,您第二次打电话时也应该发生同样的事情。chicken1.eggs_lifetime()
1赞 juanpa.arrivillaga 8/4/2023
请,将来当您提出问题时,如果您遇到错误,请务必发布完整的错误消息,包括堆栈跟踪。python 运行时不遗余力地提供这一点,因为它有助于调试。
0赞 juanpa.arrivillaga 8/4/2023
退后一步,你继续在可能不应该的地方创建实例变量。这就是导致您的错误的原因。通常,所有实例变量都应在 中定义。您在其他方法中创建的大多数实例变量可能只是常规局部变量__init__
0赞 Ryan R. McKnight 8/4/2023
好的,在我的函数中,我应该使用随机变量,以免不断更新实例变量。假设我希望函数更新实例变量......我会只将该变量分配给函数末尾的实例变量吗?

答:

3赞 Tim Roberts 8/4/2023 #1

这是因为在你的函数中,你有eggs_week

        self.eggs_week = self.eggs_day * 7

在那之后,不再是一个功能。它是一个整数。chicken1.eggs_week

您实际上不需要在函数名称中包含前缀,因为它已经是一个与 eggs 相关的类。此外,您计算的大多数值不需要在对象中保存为状态,因此它们不需要 。self.

更多此类内容:

class EggLayers(Animal):
    """A class for egg laying animals"""
    type = "chicken"

    def __init__(self, name, age, color, tag):
        super().__init__(name, age, color, tag)
        self.eggs_list = []

    def per_week(self):    # to calculate eggs/week and then append to list
        eggs_day = int(input("Eggs today?  "))
        eggs_week = eggs_day * 7
        self.eggs_list.append(eggs_week)
        print(f"{self.name} laid {eggs_week} this week")
        return eggs_week

    def lifetime(self):  # to sum the values in the list above
        eggs_lifetime = sum(self.eggs_list)
        print(f"Liftetime production for {self.name} is {eggs_lifetime}")
        return eggs_lifetime

就我个人而言,我认为在这样的类方法中进行 I/O 是一种不好的做法。该类应包含与对象直接相关的功能。它不应该关心信息来自哪里。例如,现在,您不能轻松地使用它从文件或数据库中读取数据。

我会在类外有一个循环来请求输入,然后有一个类方法允许我传递该信息,例如 .但是,我没有在这里进行更改。add_week

评论

1赞 juanpa.arrivillaga 8/4/2023
我要强调的是,您停止了对实例属性的赋值,而是在方法中使用了局部变量
0赞 Ryan R. McKnight 8/4/2023
啊,所以要清楚,因为我的函数名和变量名是相同的,所以一个替换另一个。完全有道理。我一直在想,函数名称后面的()会将其与同名变量区分开来。非常感谢!
0赞 Tim Roberts 8/4/2023
不,所有的名字都是一样的。一个对象只有一个命名空间。同样的事情也发生在全球层面。说将从您的使用中删除正常的文件功能。open = 7open
0赞 juanpa.arrivillaga 8/4/2023
@RyanR.McKnight本质上就像一个操作员。它作用于表达式的结果,表达式也是如此,它产生一个对象。然后,尝试调用该对象。但在本例中,是 ,但对象不可调用。你可以通过这样做得到同样的错误()self.whatever()self.whaeterintintf = 42print(f())