Sympy类Zero,One和NegativeOne,为什么它们存在?

Mr.*_*. E 9 python sympy

今天我发现了这个

>>> type(1)
<class 'sympy.core.numbers.One'>
>>> type(0)
<class 'sympy.core.numbers.Zero'>
>>> type(-1)
<class 'sympy.core.numbers.NegativeOne'>
>>> type(2)
<class 'sympy.core.numbers.Integer'>
Run Code Online (Sandbox Code Playgroud)

从同意这些类型的文档中查看了文档,但它没有说明它们存在的原因.是否有理由为-1,0和1设置3个特殊单例类?

编辑:我在SymPy在线shell看到了这个

unu*_*tbu 5

SymPy中的每个数字都由该类 Number的实例表示. Floats,Integers和Rationals是.的子类Number.Zero是.的子类Integer.

您可以通过调用其类mro(方法解析顺序)方法来检查对象的完整类谱系:

In [34]: from sympy import S
In [38]: type(S.Zero).mro()
Out[38]: 
[sympy.core.numbers.Zero,
 sympy.core.numbers.IntegerConstant,
 sympy.core.numbers.Integer,            <-- Zero is a kind of Integer
 sympy.core.numbers.Rational,
 sympy.core.numbers.Number,
 sympy.core.expr.AtomicExpr,
 sympy.core.basic.Atom,
 sympy.core.expr.Expr,
 sympy.core.basic.Basic,
 sympy.core.evalf.EvalfMixin,
 object]
Run Code Online (Sandbox Code Playgroud)

这些子类"教"SymPy如何象征性地操作和简化表达式.作为示例,Rational类的实例以这种方式否定:

def __neg__(self):
    return Rational(-self.p, self.q)
Run Code Online (Sandbox Code Playgroud)

也就是说,如果x是实例Rational,则-x导致x.__neg__()被调用.与此同时,Integer班级的实例被否定了

def __neg__(self):
    return Integer(-self.p)
Run Code Online (Sandbox Code Playgroud)

如果对象特别是一个实例Zero,那么它的否定定义为:

@staticmethod
def __neg__():
    return S.Zero    # the negation of Zero is still Zero
Run Code Online (Sandbox Code Playgroud)

Zero,One并且MinusOne还实现_eval_power其中"教导"这些对象如何评价方法x的幂(其中xZero,OneMinusOne).例如,Zero提升到正面表达式等于自己:

def _eval_power(self, expt):
    if expt.is_positive:
        return self
    ...
Run Code Online (Sandbox Code Playgroud)

One提升到任何事情都等于自己:

def _eval_power(self, expt):
    return self
Run Code Online (Sandbox Code Playgroud)

如果你仔细阅读源代码sympy.core.numbers模块,你会发现教学SymPy怎么做象征性的算术定义它们是有效载荷.它与数学课上的儿童教学并没有太大的不同,只是它用计算机表达.

您可能想知道为什么每个整数都没有特殊的类. Integers此外Zero,One并被MinusOne视为一般Integer类的实例.他们的加法和乘法规则等都列在那里.与模块加载时不同Zero,One并且只在需要时MinusOne缓存其他整数:

def __new__(cls, i):
    ...
    try:
        return _intcache[ival]   # <-- return the cached Integer if seen before
    except KeyError:           
        obj = Expr.__new__(cls)  # <-- create a new Integer if ival not in _intcache
        obj.p = ival

        _intcache[ival] = obj
        return obj
Run Code Online (Sandbox Code Playgroud)