【问题标题】:Python: using classes outputs an errorPython:使用类输出错误
【发布时间】:2013-01-11 17:39:50
【问题描述】:

我正在尝试用 python 制作一个非常简单的计算器。在只使用函数之前我已经做了一个工作,但事实证明添加类很困难。

def askuser():
    global Question, x, y

    Question = input("""Enter a word: ("Add", "Subtract", "Multiply", "Divise")""")
    x = int(input("Enter first number: "))
    y = int(input("Enter second number: "))

class calculating:

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def add(self):
        return self.x + self.y

    def subtract(self):
        return self.x - self.y

    def multiplication(self):
        return self.x * self.y

    def division(self):
        return self.x / self.y

math = calculating

def calc():

    if Question == "Add":
        t = math.add
        print(t)

    elif Question == "Subtract":
        t = math.subtract
        print(t)

    elif Question == "Multiply":
        t = math.multiplication
        print(t)

    elif Question == "Division":
        t = math.division
        print(t)

def final():
    input("Press any key to exit:" )


def main():

    askuser()
    calc()
    final()

main()

代码运行良好,但它给了我一个“错误”而不是输出一个计算:

   Enter a word: ("Add", "Subtract", "Multiply", "Divise")Add

   Enter first number: 5

   Enter second number: 5

   function add at 0x02E4EC90

   Press any key to exit:

为什么会这样?任何帮助都会很棒,谢谢。

【问题讨论】:

    标签: python class


    【解决方案1】:

    您正在打印函数本身,而不是调用它的结果。试试:

    def calc():
    
    if Question == "Add":
        t = math.add
    
    elif Question == "Subtract":
        t = math.subtract
    
    elif Question == "Multiply":
        t = math.multiplication
    
    elif Question == "Division":
        t = math.division
    
    print t()
    

    或者更简洁但更高级:

    class UserInputCalculator(object):
    
        operations = ["Add", "Subtract", "Multiply", "Divide"]
    
        def __init__(self):
            self.x = None
            self.y = None
            self.operation = None
    
        def run(self):
            self.prompt_for_operation()
            self.prompt_for_x()
            self.prompt_for_y()
            if self.operation == 'Add':
                return self.add()
            elif self.operation == 'Subtract':
                return self.subtract()
            elif self.operation == 'Multiply':
                return self.multiply()
            elif self.operation = 'Divide':
                return self.divide()
            else:
                raise ValueError('Unknown operation %s.' % operation)
    
        def prompt_for_operation(self):
            self.operation = input("Enter an operation: (%s)" % ', '.join(UserInputCalculator.operations))
            if self.operation not in UserInputCalculator.operations:
                raise ValueError('%s not a valid operation.' % self.operation)
            return self.operation
    
        def prompt_for_x(self):
            try:
                self.x = int(input("Enter first number: "))
            except:
                raise ValueError('Invalid value.')
            return self.x
    
        def prompt_for_y(self):
            try:
                self.y = int(input("Enter second number: "))
            except:
                raise ValueError('Invalid value.')
            return self.y
    
        def add(self):
            return self.x + self.y
    
        def subtract(self):
            return self.x - self.y
    
        def multiply(self):
            return self.x * self.y
    
        def divide(self):
            return self.x / self.y
    
    calculator = UserInputCalculator()
    print calculator.run()
    input("Press any key to exit:" )
    

    【讨论】:

    • 非常感谢。您的代码由于某种原因不起作用,它返回“NameError:未定义全局名称'操作'”。然而,我将我的代码重写为类似你的代码,它终于可以工作了!干杯。
    【解决方案2】:

    行:

    t = math.multiplication
    

    将函数对象math.multiplication 分配给t,然后在下一行打印它。您需要添加() 以使函数实际执行:

    t = math.multiplication()
    

    【讨论】:

      【解决方案3】:

      另外两个答案是正确的,你实际上在这里做的是打印函数本身,而不是调用它的结果。不过,我认为您应该重新考虑该程序的结构,并问自己为什么在这里使用类。一般来说,类应该是具有状态的东西,即与每个实例相关联的一个或多个变量。这需要实例化类;但是,您的代码不包含实例化(即使您定义了 __init__ 函数); math = calculating 行只是将变量 math 转换为对 class calculating 的引用(不是 instance of class )。您使用的是全局变量而不是类变量,如果您以后想将此模块作为更大程序的一部分导入,这可能会出现问题(实际上,全局变量在大多数情况下通常不是一个好主意)。

      因此,我建议将函数视为接受一组特定变量并返回其他一组变量的东西,而不是这种结构。这不是考虑函数的唯一方法,但在这个简单的计算器示例中,它可能是最好的方法。

      让我们从上往下看。您的 main 函数可能如下所示:

      def main():
          (q,x,y) = askuser()
          ans = math[q](x,y)
          final(ans)
      

      请注意,我在这里所做的是将每个函数的结果传递给下一个函数。另请注意,我现在使用 math 的语法有所不同;我将使用函数字典而不是函数类。

      那么我们来看看如何实现main调用的函数。首先,askuser 将与您代码中的原始版本相同,只是它包含global 声明。

      其次,math 将是一个字典,定义如下:

      def add(x,y):
          return x + y
      
      def subtract(x,y):
          return x - y
      
      def multiply(x,y):
          return x * y
      
      def divide(x,y):
          return x / y
      
      math = {"Add" : add,
              "Subtract" : subtract,
              "Multiply" : multiply,
              "Divide" : divide}
      

      最后,final 应该打印出答案:

      def final(ans):
          print ans
          input("Press any key to exit:" )
      

      这通常比您的解决方案干净得多。但是,如果您想学习如何很好地使用类,它对您没有多大帮助。所以想想你到底想要你的类的状态是什么,然后以这种方式实现你的代码。例如,您可以通过这种方式添加一个类calculator

      class calculator:
          def compute(x,y):
              print "No operation defined!"
      
          def __init__(self,operation):
              if operation in math:
                  self.compute = math[operation]
              else:
                  print "%s is not a valid operation!"%operation
      

      main 将如下所示:

      def main():
          (q,x,y) = askuser()
          mycalc = calculator(q)
          ans = mycalc(x,y)
          final(ans)
      

      【讨论】:

      • 类的成员在内部存储在字典中,因此所有将函数放入字典中所做的只是提供一个穷人的类结构,除了接口更钝、功能更少、周围有用的工具它。有时在字典中删除函数是一个更好的解决方案,但这不是你应该教入门程序员做的事情。进行函数式编程或面向对象编程,但不要仅仅因为可以就将伪 oo 行为强加到函数式编程结构中。
      • 提问者将类用作多个功能的容器。他们并没有以一种很好的方式使用它,所以真正的类的额外功能和功能对他们没有任何好处。手动编写类似 switch 语句的逻辑来访问(静态)类成员而不是仅使用实际的内置容器类型是没有意义的。
      • 如果您正在尝试学习课程的基础知识,它会起作用。试图将高级软件设计原则应用于仅用于说明基本语法概念的玩具示例是没有意义的。您不妨说他应该使用lowergetattr 直接将操作映射到函数名称。这实际上并不能帮助他学习他不知道的东西。此外,您在谈论风格和实践,甚至没有遵循 PEP8。最后,有状态的,或者至少是状态变化的对象并不是唯一有用的对象。以re.MatchObject 为例。
      • 如果“类的基础知识”是指“如何将类用作命名空间”,那么是的,原始代码演示了这一点,但在我看来,这并不是一个很好的演示使用类,所以我建议不要使用它们。与此同时,字典似乎是 Python 的一个非常基本的组件(即使每个条目中包含的数据都是一个函数),并且明智地使用字典通常比定义新类更有用。但是,我还解释了如何(更有用地)在此示例中使用类。那么有什么问题呢?
      • (至于 PEP8:我在我的代码中没有看到任何违反 PEP8 的内容,除非我没有大写 calculator,并且字符串文字的 "blah %s"%value 语法是 no不再是将值放入字符串的首选方法,但这些似乎都不是特别相关的问题。至于MatchObject,不,一旦初始化它就无法更改对象的状态,但它仍然会绑定数据到功能,这是oo编程的核心思想。)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多