【问题标题】:Calling a class method raises a TypeError in Python在 Python 中调用类方法会引发 TypeError
【发布时间】:2010-09-28 15:39:33
【问题描述】:

我不明白如何使用类。当我尝试使用该类时,以下代码给了我一个错误。

class MyStuff:
    def average(a, b, c): # Get the average of three numbers
        result = a + b + c
        result = result / 3
        return result

# Now use the function `average` from the `MyStuff` class
print(MyStuff.average(9, 18, 27))

错误:

File "class.py", line 7, in <module>
    print(MyStuff.average(9, 18, 27))
TypeError: unbound method average() must be called with MyStuff instance as first argument (got int instance instead)

怎么了?

【问题讨论】:

  • 将课程视为模具。您实际上并不与模具本身进行交互,但您使用模具来创建对象,然后您可以与之交互。为了对对象做一些事情,你必须先创建它。

标签: python python-3.x class methods


【解决方案1】:

您可以通过声明一个变量并像调用函数一样调用该类来实例化该类:

x = mystuff()
print x.average(9,18,27)

但是,这不适用于您提供给我们的代码。当您在给定对象 (x) 上调用类方法时,它总是在调用函数时将指向该对象的指针作为第一个参数传递。所以如果你现在运行你的代码,你会看到这个错误信息:

TypeError: average() takes exactly 3 arguments (4 given)

要解决此问题,您需要修改平均方法的定义以采用四个参数。第一个参数是对象引用,剩下的 3 个参数用于 3 个数字。

【讨论】:

  • 你的意思是它应该接受参数 self 吗?
  • 您可以随意调用它。 “self”只是一个约定。
  • @JoshSmeaton 你真的应该使用“self”,因为即使它在技术上不是必需的,但它是一个非常标准的约定,会让你的代码在其他 python 开发人员中更加主流。
【解决方案2】:

从您的示例来看,在我看来您想使用静态方法。

class mystuff:
  @staticmethod
  def average(a,b,c): #get the average of three numbers
    result=a+b+c
    result=result/3
    return result

print mystuff.average(9,18,27)

请注意,在 python 中大量使用静态方法通常是一些不良气味的症状 - 如果您真的需要函数,那么直接在模块级别声明它们。

【讨论】:

  • 很抱歉投了反对票,但我认为您误解了这个问题。看来 stu 是 Python 的新手,所以将他引导到有关 Python 基础的优秀资源可能比向他展示如何使用静态方法更好;)
  • 另一方面,python 中对“self”的显式使用以及对静态方法的错误信念对于来自其他语言的人来说是一个很常见的陷阱。由于这里的许多人都指向文档和资源,我认为应该至少有一个“直接”的答复。感谢您的评论!
  • 除非你正在制作一个实用类,它可以很好地制作很多静态和类方法
【解决方案3】:

为了尽量减少您的示例,您可以将代码修改为:

class myclass(object):
        def __init__(self): # this method creates the class object.
                pass

        def average(self,a,b,c): #get the average of three numbers
                result=a+b+c
                result=result/3
                return result


mystuff=myclass()  # by default the __init__ method is then called.      
print mystuff.average(a,b,c)

或者更全面地扩展它,允许您添加其他方法。

class myclass(object):
        def __init__(self,a,b,c):
                self.a=a
                self.b=b
                self.c=c
        def average(self): #get the average of three numbers
                result=self.a+self.b+self.c
                result=result/3
                return result

a=9
b=18
c=27
mystuff=myclass(a, b, c)        
print mystuff.average()

【讨论】:

  • 我们只做myclass().average(a,b,c)可以吗?
  • @DJ_Stuffy_K 该代码适用于我的第一个代码示例。但是最初的问题与实例化类有关,所以我包含了 def __init__() 方法。您的代码 sn-p 实例化了该类,但没有“句柄”可供访问可能使用相同实例变量的其他方法。也许这有帮助。
【解决方案4】:

类中的每个函数,以及每个类变量都必须采用 self 参数。

class mystuff:
    def average(a,b,c): #get the average of three numbers
            result=a+b+c
            result=result/3
            return result
    def sum(self,a,b):
            return a+b


print mystuff.average(9,18,27) # should raise error
print mystuff.sum(18,27) # should be ok

如果涉及类变量:

 class mystuff:
    def setVariables(self,a,b):
            self.x = a
            self.y = b
            return a+b
    def mult(self):
            return x * y  # This line will raise an error
    def sum(self):
            return self.x + self.y

 print mystuff.setVariables(9,18) # Setting mystuff.x and mystuff.y
 print mystuff.mult() # should raise error
 print mystuff.sum()  # should be ok

【讨论】:

    【解决方案5】:

    您需要多花一点时间在面向对象编程的一些基础知识上。

    这听起来很苛刻,但很重要。

    • 您的类定义不正确——尽管语法恰好是可以接受的。定义是完全错误的。

    • 您完全没有使用类来创建对象。

    • 您使用类进行计算是不合适的。这种事情可以做,但是需要@staticmehod这个高级概念。

    由于您的示例代码在很多方面都存在错误,因此您无法得到一个整洁的“解决此问题”的答案。有太多的事情要解决。

    您需要查看更好的类定义示例。目前尚不清楚您使用什么源材料来学习,但无论您阅读的书是错误的还是不完整的。

    请丢弃您正在使用的任何书籍或资源并找到更好的书籍。严重地。他们在类定义的外观和使用方式上误导了您。

    您可能想查看http://homepage.mac.com/s_lott/books/nonprog/htmlchunks/pt11.html 以获得对类、对象和 Python 的更好介绍。

    【讨论】:

    • 这个链接现在失效了。我可以改用课程/书名吗?
    【解决方案6】:

    在类的python成员函数中需要显式的self参数。与 C++ 中的隐式 this 指针相同。更多详情请查看this页面。

    【讨论】:

    • 不同意。不是强制性的是“自我”的名称。但是 Python 成员函数的第一个参数是对对象的引用。当然你有类和静态方法,但是对于实例方法,规则适用。
    • @Abgan:实际上,它甚至适用于类和静态方法——装饰器只是做一些自动处理,以便被包装的函数接收与包装器不同的参数。
    【解决方案7】:

    试试这个:

    class mystuff:
        def average(_,a,b,c): #get the average of three numbers
                result=a+b+c
                result=result/3
                return result
    
    #now use the function average from the mystuff class
    print mystuff.average(9,18,27)
    

    或者这个:

    class mystuff:
        def average(self,a,b,c): #get the average of three numbers
                result=a+b+c
                result=result/3
                return result
    
    #now use the function average from the mystuff class
    print mystuff.average(9,18,27)
    

    【讨论】:

      【解决方案8】:

      您从未创建过实例。

      您已将平均定义为实例方法,因此,要使用平均,您需要先创建一个实例。

      【讨论】:

      • 很抱歉投了反对票;你是绝对正确的,但这不是一个很有帮助的答案
      • 问题的字面意思是“怎么了?”这个答案确实说明了问题所在,所以我认为这是一个答案。
      • @recursive (回应 7 年后的评论,2 年后)我认为真正的问题在于标题,字面意思是“如何实例化一个类”。在尝试学习如何创建实例时指出您需要创建实例是没有帮助的;根据上下文(标题)说这是一个答案是迂腐的。您甚至没有详细说明或指导正确的答案,而是其他人为您做的。在某些时候,我们对编程和措辞问题都很陌生。
      猜你喜欢
      • 2017-04-17
      • 2018-03-12
      • 2012-12-06
      • 1970-01-01
      • 1970-01-01
      • 2018-12-08
      • 1970-01-01
      • 1970-01-01
      • 2017-01-11
      相关资源
      最近更新 更多