是否可以覆盖 SageMath 中现有数据类型的漂亮打印?

问题描述 投票:0回答:1

在IPython中,使用如何配置ipython以十六进制格式显示整数?中的方法,可以自定义对象的打印方式:

In [1]: import ast
   ...: formatter=get_ipython().display_formatter.formatters["text/plain"]
   ...: formatter.for_type(ast.AST, lambda o, p, cycle: p.text("??"))
Out[1]: <function __main__.<lambda>(o, p, cycle)>

In [2]: x=ast.parse('1+2')

In [3]: x
Out[3]: ??

在SageMath中,同样的方法不起作用:

sage: import ast
....: formatter=get_ipython().display_formatter.formatters["text/plain"]
....: formatter.for_type(ast.AST, lambda o, p, cycle: p.text("??"))
....: x=ast.parse('1+2')
sage: x
<ast.Module object at 0x7f5750ccfaf0>

对于自定义类,似乎可以使用

_repr_
__repr__
(前者仅当对象继承自
SageObject
时):

sage: class A(SageObject):
....: ^Idef _repr_(self)->str:
....: ^I^Ireturn "abc"
....: A()
abc
sage: class A:
....: ^Idef __repr__(self)->str:
....: ^I^Ireturn "abc"
....: A()
abc
sage: ast.AST.__repr__=lambda x: "??"  # hack, patch Python method
sage: x=ast.parse('1+2')
sage: x
??

如果我想自定义现有 SageMath 类的方式,例如,这不起作用

sage: from sage.rings.complex_interval import ComplexIntervalFieldElement
sage: ComplexIntervalFieldElement.__repr__=lambda x: "??"
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[30], line 1
----> 1 ComplexIntervalFieldElement.__repr__=lambda x: "??"

TypeError: cannot set '__repr__' attribute of immutable type 'sage.rings.complex_interval.ComplexIntervalFieldElement'

因此,总而言之,是否可以自定义如何在输出中打印

CIF
或其他 SageMath 类型

python sage
1个回答
0
投票

这个答案在某些情况下有效,但有局限性。

翻看SageMath源代码,漂亮打印的工作方式是:

  • SageDisplayFormatter
    .format()
    方法 →
  • DisplayManager
    .displayhook()
    方法 →
  • DisplayManager
    ._rich_output_formatter()
    方法 →
  • BackendIPythonCommandline
    .plain_text_formatter()
    方法(仅当对象上不存在
    _rich_repr_
    方法时)(此硬编码
    SagePrettyPrinter
    用作下面的
    pretty_printer_class
    )→
  • BackendBase
    ._apply_pretty_printer()
    方法 →
  • 构造
    pretty_printer_class
    对象的新实例,并对其调用
    .pretty()
  • SagePrettyPrinter
    .pretty()
    方法 →
  • 迭代
    SagePrettyPrinter.pretty_repr
    列表中的对象 →
  • SomeIPythonRepr
    .__call__()
    方法 →
  • self._type_repr
    中查找类型。

请注意,

SomeIPythonRepr
可能会被覆盖,请通过设置检查使用哪一个:

from sage.repl.display.pretty_print import SagePrettyPrinter
SagePrettyPrinter.DEBUG=True

因此,我们修改列表(请注意,这会访问内部属性,这可能会破坏)

sage: from sage.repl.display.pretty_print import SagePrettyPrinter
....: from sage.repl.display.fancy_repr import SomeIPythonRepr
....: import ast
....: someIPythonReprInstance = next(x for x in SagePrettyPrinter.pretty_repr
....:                                if isinstance(x, SomeIPythonRepr))
....: someIPythonReprInstance._type_repr[ast.Module] = lambda o, p, cycle: p.text("??")

注意,这里我们不能使用

ast.AST
,因为由于某种原因,对象的MRO没有被遍历,这与IPython不同。

然后,该类型的漂亮打印将大部分工作:

sage: ast.parse('1+2')
??

另一个例子:

sage: def printAlgebraicNumber(o: AlgebraicNumber, p: SagePrettyPrinter, cycle: bool)->None:
....:     o.exactify()
....:     p.text(repr(o))
....:     if o not in QQ:
....:         p.text(' (minpoly = ')
....:         p.pretty(o.minpoly())
....:         p.text(')')
sage: QQbar(sqrt(2))
1.414213562373095? (minpoly = x^2 - 2)

请注意,这有一些性能影响——每次打印

QQbar
的元素时,它都是精确的(即使未显式调用
exactify()
,也需要检查该元素是否属于有理数)。

如果不起作用,请尝试设置

DEBUG
选项(见上文)以查看使用的是哪款漂亮的打印机 - 如果有的话。


潜在有用:

  • get_ipython().display_formatter
    返回
    SageDisplayFormatter
    实例
  • sage.repl.rich_output.get_display_manager()
    返回
    DisplayManager
    单例实例,相当于
    get_ipython().display_formatter.dm
© www.soinside.com 2019 - 2024. All rights reserved.