今天我发现了这个
>>> 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'>
我看了documentation from sympy关于这些类型的内容,但它没有说明它们存在的原因。是否有理由为-1,0和1设置3个特殊单例类?
编辑:我在SymPy online shell
看到了这一点答案 0 :(得分:5)
SymPy中的每个数字都由the class
Number
的实例表示。
Float
s,Integer
和Rational
是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]
这些子类&#34;教导&#34; SymPy如何象征性地操纵和简化表达式。作为一个 例如,Rational类的实例是negated this way:
def __neg__(self):
return Rational(-self.p, self.q)
也就是说,如果x
是Rational
的实例,那么-x
会导致x.__neg__()
被调用。同时,Integer
类的实例为negated by
def __neg__(self):
return Integer(-self.p)
如果对象特别是Zero
的实例,那么its negation就是。{
定义如下:
@staticmethod
def __neg__():
return S.Zero # the negation of Zero is still Zero
Zero
,One
和MinusOne
也实施了_eval_power
方法
&#34;教导&#34;这些对象如何评估x
提升到权力(x
所在的位置
Zero
,One
或MinusOne
)。例如,Zero
raised to a positive
expression等于自己:
def _eval_power(self, expt):
if expt.is_positive:
return self
...
def _eval_power(self, expt):
return self
如果您仔细阅读sympy.core.numbers
模块the source code,则可以找到
实际上教导SymPy如何做符号的定义
算术。它与数学课上的孩子教学方式没什么不同,只不过它是用计算机表达的。
您可能想知道为什么没有针对每个整数的特殊类。
除Integers
之外的Zero
,One
和MinusOne
被视为该实例
一般Integer
类。他们的加法和乘法规则等都列在那里。与加载模块时即时创建的Zero
,One
和MinusOne
不同,其他整数被缓存only as needed:
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
答案 1 :(得分:3)
首先,请注意type(1)
为您提供了type(Integer(1))
,因为SymPy Live会自动包装Integer()
中的整数文字(这是为了避免gotcha 1/2
评估到0.5
而不是Rational(1, 2)
)。但请注意,在常规Python会话中,type(1)
为int
。
SymPy中有几个对象实现为单例,这意味着只存在一个实例。您可以在S
对象
In [13]: dir(S)
Out[13]:
['Catalan',
'ComplexInfinity',
'Complexes',
'EulerGamma',
'Exp1',
'GoldenRatio',
'Half',
'IdentityFunction',
'ImaginaryUnit',
'Infinity',
'NaN',
'Naturals0',
'NegativeInfinity',
'NegativeOne',
'One',
'Pi',
'Reals',
'Zero',
'__call__',
'__class__',
'__delattr__',
'__doc__',
'__format__',
'__getattr__',
'__getattribute__',
'__hash__',
'__init__',
'__module__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__slots__',
'__str__',
'__subclasshook__',
'_classes_to_install',
'false',
'register',
'true']
(忽略以_
开头的那些;那些是Python内部方法)
这样做的原因是这些对象被大量使用。 0,1和-1是非常常见的对象。每次撰写1/x
时,它都会在内部表示为Pow(x, -1)
。 x - y
表示为Add(x, Mul(-1, y))
。对于0,它经常出现在各种符号计算中。 1也很常见。通过使用单个实例,SymPy可以实现两个优化。首先,它节省了内存。其次,您可以使用is
比较来比较这些对象,例如x is S.One
。因为只有一个实例可以存在Integer(1)
始终与S.One
相同。
(另外,我应该注意S
中的某些对象实际上并不常见,例如Catalan
和EulerGamma
。我猜他们为了方便而添加了更多内容。 )