【问题标题】:Can I use an overloaded operator in the class declaration?我可以在类声明中使用重载运算符吗?
【发布时间】:2019-11-09 22:29:53
【问题描述】:

我正在尝试在 python 中创建一个简单的 Vector 类,但我意识到我不能在像 c++ 这样的方法中使用以前重载的运算符。我有什么错误吗?或者它是如何工作的?

class Vector3D:
    #constructor
    def __init__(self,x,y,z):
        self.x = x
        self.y = y
        self.z = z
    #overloading division operator for just numbers
    def __div__(self,other):
        if type(other) == int or type(other) == float:
            return Vector3D(self.x/other,self.y/other,self.z/other)
        print("Error")
        return
    #Used in the normalize method
    def Magnitude(self):
        return math.sqrt(self.x**2+ self.y**2 + self.z**2)
    # ==> using the division operator in normalization
    def Normalize(self):
        return self / self.Magnitude()
    # <== Throws: TypeError: unsupported operand type(s) for /: 'Vector3D' and 'float'

【问题讨论】:

  • __div__ 在 Python 3 中不是一个东西。__truediv__ 对应于/__floordiv__ 对应于//
  • @user2357112 谢谢我不知道:D
  • 这里有一些其他提示:被覆盖的数学运算符如果不知道该做什么应该return NotImplemented(然后Python 将检查其他操作数是否支持适当的操作)。而不是检查type(other) ==,您可以使用isinstancenumbers 模块中的抽象基数类:isinstance(other, numbers.Number)
  • @jirassimok 操作实现; TypeError 会更合适,就像 float.__rdiv__ 现在正在加注一样。
  • @chepner float 的操作员不会引发TypeError,他们会返回NotImplemented(尝试(1.0).__truediv__(None))。如果两个操作数都返回NotImplemented,Python 会自动生成TypeError。如果您在__truediv__ 中手动提出TypeError,您会阻止其他类能够划分您的类,即使它们实现了__rtruediv__

标签: python class operator-overloading


【解决方案1】:

在 Python 3 中,将__truediv__ 用于/,将__floordiv__ 用于//

这也适用于带有from __future__ import division 的 Python 2(这使得除法的行为与 Python 3 中一样)。


这里有两条额外的建议:

首先,您可以使用numbers 模块中的类来检查数字类型,而不是检查确切的类型floatint

其次,如果它不知道如何处理给定值,则应该从重写的二元运算符返回NotImplemented。然后,Python 将检查另一个操作数是否实现了运算符的翻转版本(即__r[name]__)并尝试。如果这也返回NotImplemented,Python 将引发TypeError。这允许您创建可以在运算符两侧使用的类。

import numbers

class Vector1D:
  def __init__(self, x):
    self.x = x
  def __repr__(self, x):
    return "Vector1D({})".format(self.x)

  def __mul__(self, other):
    if isinstance(other, numbers.Number):
      return self.__class__(self.x * other)
    return NotImplemented

  def __rmul__(self, other):
    # x * vec1d == vec1d * x
    return self.__mul__(other)

  def __rtruediv__(self, other):
    # You can't divide things by a Vector1D
    return NotImplemented

vec2 = Vector1D(2)

vec2 * 3
# Runs vec2.__mul__(2), gets Vector1D(6)

3 * vec2
# First tries int.__mul__(3, vec2), gets NotImplemented
# Then tries Vector1D.__rmul__(vec2, 3), gets Vector1D(6)

3 / vec2
# First tries int.__truediv__(3, vec2), gets NotImplemented
# Then tries Vector1D.__rtruediv__(vec2, 3), gets NotImplemented
# Python raises TypeError

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-16
    相关资源
    最近更新 更多