如何(Sanely)延伸同情.Rational

时间:2016-03-08 15:16:34

标签: python inheritance sympy

是否有一种理智的方式来获取和使用MixedNumbers而不是不正确的分数? (我正在使用乳胶输出并为1/4 + 2 1/3 =等问题的小学生生成pdf。)

我正在尝试创建一个在SymPy中使用的MixedRational(或MixedNumber或MixedFraction)类。 This是我能找到的与SymPy中混合表示相关的唯一线程。

我希望我的MixedRational类有2个成员变量:i和f,对于混合数字的整数和小数部分,并且有适当的方法,如__str__,以便它以混合数字打印。 / p>

但是,我无法克服这条道路上的第一道障碍,即根本无法继承Rational的能力。覆盖__new__似乎是一个要求,因为Rational.__new__(cls, *args)返回一个感觉类型的实例,而不是返回类型为cls的实例(为什么Attempt 0失败)。

我基于提供的args创建了一个新的Rational并将其存储在MixedNumber中,并以某种方式透明地访问了MixedNumber没有定义的函数和变量(尝试1,2,3),但我还没有我尝试过的任何方法都取得了成功。

因为当Rational.__new__(cls, *args)实际返回Rational(而不是Integer或One或Zero)时,我可以让Rational的子类表现得很好,所以我几乎准备编写5个单独的类(MixedNumber,MixedRational,MixedInteger) ,MixedOne,MixedZero),MixedNumber.__new__(cls, *args)调用Rational.__new__(cls, *args),然后根据类型Rational.__new__确定要实例化的Mixed *类。

但是,我觉得我必须过于复杂。

from sympy import *
class MixedNumber(Rational):
    def __new__(cls, *args):
        #Attempt 3
        rational_instance = Rational.__new__(cls, *args)
        rational_instance.__class__ = cls
        return rational_instance

        #Attempt 2
        #rational_instance = Rational.__new__(cls, *args)
        #mixed_instance = object.__new__(cls)
        #mixed_instance.my_rational = rational_instance
        #print("dict")
        #return mixed_instance

        #Attempt 1
        #rational_instance = Rational.__new__(cls, *args)
        #mixed_instance = object.__new__(cls)
        #mixed_instance.__dict__.update(rational_instance.__dict__)
        #return mixed_instance

        #Attempt 0
        #return Rational.__new__(cls, *args)    
    def __init__(self, *args):
        # print(self.__dict__)
        # print(self.my_rational)
        self.my_rational.__init__(*args)
    #Attempt 2  
    #def __getattr__(self, attr):
    #   print("Attr=", attr)
    #   print("Dict=",self.__dict__)
    #   import time
    #   time.sleep(1)
    #   try:
    #       return self.__dict__[attr]
    #   except KeyError:
    #       return getattr(self.my_rational, attr)
x = Rational(0,1)
print(x)
print(type(x))
print(x.p)
print(x.q)
y = Rational(3,1)
print(y)
print(type(y))
print(y.p)
print(y.q)
z = Rational(15,4)
print(z)
print(type(z))
print(z.p)
print(z.q)
x = MixedNumber(0,1)
print(x)
print(type(x))
print(x.p)
print(x.q)
y = MixedNumber(3,1)
print(y)
print(type(y))
print(y.p)
print(y.q)
z = MixedNumber(15,4)
print(z)
print(type(z))
print(z.p)
print(z.q)

1 个答案:

答案 0 :(得分:2)

我认为尝试将Rational子类化是徒劳的。如此多的SymPy函数都使用Rational进行硬编码,即使您创建了一个成功的子类,只要对表达式执行任何操作,都会将其再次移回Rational

相反,您应该修改打印机,以便按照您希望的方式打印。根据您使用的打印机,您应该将该打印机子类化,并覆盖_print_Rational。请参阅documentation。既然提到了latex,你就会继承LatexPrinter并覆盖_print_Rational(self, expr)以不正确的形式打印expr(理性)。使用self._print递归打印子表达式。

然后,您将使用YourPrinter().doprint(expr)打印表达式,而不是默认的latex(expr)(这是LatexPrinter().doprint(expr)的简写)。

在对打印机进行子类化时,查看original implementation(乳胶打印机位于latex.py)会很有用。在撰写本文时,这是LatexPrinter._print_Rational的默认实现

def _print_Rational(self, expr):
    if expr.q != 1:
        sign = ""
        p = expr.p
        if expr.p < 0:
            sign = "- "
            p = -p
        return r"%s\frac{%d}{%d}" % (sign, p, expr.q)
    else:
        return self._print(expr.p)