使用 类 减法时如何 return 负分数?

How to return a negative fraction when subtracting with use of classes?

在我的部分代码中,我可以减去分数,但是如果我输入 (- p),其中 p 是分数,我会得到 TypeError: unsupported operand type(s) for +: "Fraction" and "Fraction"

def gcd(denominator, numerator):
    if numerator == 0:
        return denominator
    else:
        return gcd(numerator, (denominator % numerator))

class Fraction:
    
    def __init__(self,numerator = 0, denominator = 1):

        self.numerator = int(numerator / gcd(abs(denominator),abs(numerator) ))
        self.denominator = int(denominator / gcd(abs(denominator),abs(numerator) ))
        if self.denominator < 0:
            self.denominator = abs(self.denominator)
            self.numerator = -1*self.numerator
        elif self.denominator == 0:
            raise ZeroDivisionError
        
    def __str__(self):
        if self.denominator == 1:
            return str(self.numerator)
        else:
            return str(self.numerator) + "/" + str(self.denominator)
    
    def __rsub__(self,other):
        return self.__sub__(other)

    def __sub__(self,other):
        if type(other) == int:
            other = Fraction(other,1)
            return self.sub(other)
        else:
            
            return self.sub(other)
    
    def sub(self,other):
        result = Fraction()
        
        result.numerator = other.denominator * self.numerator - self.denominator * other.numerator
        result.denominator = other.denominator * self.denominator
        
        multiple = gcd(result.denominator,result.numerator)
        
        result.numerator = int(result.numerator / multiple)
        result.denominator = int(result.denominator / multiple)
        
        return result

p = Fraction(2,3)

r = (- p)

但是,当我的输入是 (1 - p) 时,我得到了正确的输出。假设 p = Fraction(2, 3) 那么我想 (- p) 到 return (-2 / 3) 或 (2/ -3)。在我看来,问题在于减法时没有为第一个参数提供输入。在搜索时我确实遇到了 __neg__ 之类的东西,但我对 python 和使用 类 还是个新手,所以我不知道如何实现它。有谁知道我该如何解决这个问题?

提前致谢!

你的__rsub__代码被翻转了,你想要other.__sub__(self)

    def __rsub__(self,other):
        return other.__sub__(self)

你是对的;您需要实施 __neg__ 因为减号不是(二元)减法运算符,而是一元减号。

这里是你如何做到的:

    def __neg__(self):
        return Fraction(-self.numerator, self.denominator)

其他问题

__rsub__

您需要更改 __rsub__ 的实现,因为当 other 不支持 __sub__ 时将调用该方法。例如,当你评估这个时它会启动:

p = 1 - Fraction(2, 3)

该评估将无法按目前的情况进行。你需要有这个:

    def __rsub__(self, other):
        return Fraction(other) - self

或者,显式调用 __sub__:

    def __rsub__(self, other):
        return Fraction(other).__sub__(self)

规范化

构造函数正确地归一化分数,确保分母为正,但您在 sub 方法中不这样做。那里的结果可能没有标准化:分母可能保持负数。

另外,很遗憾,你复制了构造函数中已有的gcd相关代码。最好依靠构造函数来实现该逻辑。

不变性

最好将实例视为不可变的。所以你不应该在构造函数之外对 instance.numeratorinstance.denominator 进行任何赋值。确保首先确定分子和分母(没有规范化),然后然后调用构造函数将它们作为参数传递。

比较

您可能想要比较分数的相等性或相对顺序。为此,您可以实施 __eq____lt__、...等

建议代码

以下是我的做法:

def gcd(denominator, numerator):
    if numerator == 0:
        return denominator
    else:
        return gcd(numerator, denominator % numerator)

class Fraction:
    def __new__(cls, numerator=0, denominator=1):
        if isinstance(numerator, Fraction):
            return numerator  # Use this instance and ignore 2nd argument
        return super(Fraction, cls).__new__(cls)

    def __init__(self, numerator=0, denominator=1):
        if isinstance(numerator, Fraction):
            return  # self is already initialised by __new__
        if denominator == 0:
            raise ZeroDivisionError
        div = gcd(abs(denominator), abs(numerator))
        if denominator < 0:
            div = -div
        self.numerator = numerator // div
        self.denominator = denominator // div
        
    def __str__(self):
        if self.denominator == 1:
            return str(self.numerator)
        else:
            return f"{self.numerator}/{self.denominator}"
    
    def __rsub__(self, other):
        return Fraction(other) - self

    def __sub__(self, other):
        other = Fraction(other)
        return Fraction(other.denominator * self.numerator 
                             - self.denominator * other.numerator,
                        other.denominator * self.denominator)
    
    def __neg__(self):
        return Fraction(-self.numerator, self.denominator)

    def __eq__(self, other):
        other = Fraction(other)
        return (self.numerator == other.numerator and
                self.denominator == other.denominator)

    def __lt__(self, other):
        other = Fraction(other)
        return (other.denominator * self.numerator <
                     self.denominator * other.numerator)

    def __gt__(self, other):
        return Fraction(other) < self

    def __le__(self, other):
        return self < other or self == other

    def __ge__(self, other):
        return self > other or self == other