python - 如何(Sanely)扩展 sympy.Rational

标签 python inheritance sympy

是否有一种明智的方法可以在 sympy 中获取和使用混合数字而不是假分数? (我正在使用 Latex 输出并为有 1 3/4 + 2 1/3 = 等问题的小学生生成 pdf 文件)

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

我希望我的 MixedRational 类有 2 个成员变量:i 和 f,分别代表带分数的整数和小数部分,并具有适当的方法,如 __str__以便将其打印为混合数。

但是,我一直无法克服这条道路上的第一个障碍,即子类化 Rational 的能力。覆盖__new__似乎是一个要求,因为 Rational.__new__(cls, *args)返回任何类型的实例,而不是返回 cls 类型的实例(为什么尝试 0 失败)。

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

因为我可以让 Rational 的子类在 Rational.__new__(cls, *args) 时表现得理智。实际上会返回一个有理数(而不是整数或一或零),我几乎准备好编写 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)

最佳答案

我认为尝试子类化 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 打印机位于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)

关于python - 如何(Sanely)扩展 sympy.Rational,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35871158/

相关文章:

java - 使用定义的字段扩展接口(interface)?

python - pip 没有将 entry_points 安装为可执行文件

python - 在python中将整数转换为大端二进制文件

c++ - 抽象具有不同返回类型的成员函数

c# - 覆盖派生类中的构造函数,由父类(super class)的接口(interface)定义

python - Matplotlib:对于浮点来说值太小的对数刻度

Sympy 偶数和奇数的分段表达式

python-2.7 - SymPy:反函数的简化

Python - 如何打开模块内的文件?

python - 什么是 Ruby 等同于 Python 的多处理模块?