2016-01-27 12 views
9

Oggi ho trovato questoClassi Sympy Zero, One e NegativeOne, perché esistono?

>>> 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'> 

ho guardato il documentation from sympy di quei tipi, ma non dice nulla sul perché esistono. C'è una ragione per avere 3 classi speciali singleton per -1, 0 e 1?

Edit: Ho visto questo al SymPy online shell

+0

Che diamine hai fatto a ottenere 'type (1)' per essere qualcosa di diverso da 'int'? – user2357112

+0

@ user2357112 ha appena importato il modulo sympy –

+0

L'importazione di sympy non creerà problemi con il parser. 'type (1)' costruirà sempre un vero intero Python e prenderà il suo tipo, che sarà 'int'. – user2357112

risposta

5

Ogni numero SymPy è rappresentato da un'istanza di the class Number. Float s, Integer s e Rational s sono sottoclassi di Number. Zero è una sottoclasse di Integer.

è possibile ispezionare la classe stirpe pieno di un oggetto chiamando il metodo mro (ordine risoluzione dei metodi) di sua classe:

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] 

Queste sottoclassi "insegnare" SymPy come manipolare e semplificare le espressioni simbolicamente. Come esempio , le istanze della classe razionale sono negated this way:

def __neg__(self): 
    return Rational(-self.p, self.q) 

Vale a dire, se x è un'istanza di Rational, poi -x provoca x.__neg__() di essere chiamato. Nel frattempo, le istanze della classe Integer, sono negated by

def __neg__(self): 
    return Integer(-self.p) 

E se l'oggetto è, in particolare, un esempio di Zero, poi its negation è definito da:

@staticmethod 
def __neg__(): 
    return S.Zero # the negation of Zero is still Zero 

Zero, One e MinusOne implementare anche un metodo _eval_power che "insegna" questi oggetti come valutare x elevato a una potenza (dove x è Zero, One o MinusOne). Ad esempio, si Zero raised to a positive expression uguale:

def _eval_power(self, expt): 
    if expt.is_positive: 
     return self 
    ... 

One raised to anything stesso uguale:

def _eval_power(self, expt): 
    return self 

Se si sfogliare the source code per il modulo sympy.core.numbers, troverete carichi di definizioni, che sono a tutti gli effetti insegnamento SymPy come a fare simbolico aritmetica. Non è molto diverso da quello che viene insegnato ai bambini in classe matematica, tranne che è espresso in computer.

Ci si potrebbe chiedere perché non esiste una classe speciale per ogni intero. Integers oltre a Zero, One e MinusOne vengono considerati come istanze della classe generale . Le loro regole di addizione e moltiplicazione e così via sono disposte là.A differenza Zero, One e MinusOne che sono instantated quando viene caricato il modulo, altri numeri interi vengono memorizzati nella cache 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 
+0

Wow, ottima risposta. Ancora una domanda, il fatto che altri interi a fianco di 'Zero',' One' e 'NegativeOne' siano memorizzati nella cache su richiesta è il motivo per cui restituisce sempre lo stesso indirizzo di memoria (con la funzione' id')? È un po 'di "singletoning" ogni istanza di Integer? –

+1

Sì. '_intcache' è un' dict '(privato) che mappa gli interi Python in SymPy 'Integer's. Ogni volta che un 'Integer' viene istanziato,' _intcache' viene prima controllato. Se il numero intero esiste già come una chiave in '_intcache', allora viene restituito' Intero'. – unutbu

3

In primo luogo, si noti che type(1) ti ha dato type(Integer(1)) perché SymPy live avvolge letterali interi in Integer() automaticamente (questo per evitare a gotcha dove 1/2 restituisce 0.5 anziché Rational(1, 2)). Nota che in una normale sessione Python type(1) è int.

Ci sono diversi oggetti in SymPy che sono implementati come singletons, nel senso che solo un'istanza esisterà mai. Potete vedere tutti questi sul S oggetto

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'] 

(ignora quelli che iniziano con _; questi sono metodi interni Python)

La ragione per questo è fatto è che questi oggetti sono molto usati. 0, 1 e -1 sono oggetti molto comuni. Ogni volta che scrivi 1/x viene rappresentato internamente come Pow(x, -1). x - y è rappresentato come Add(x, Mul(-1, y)). Per 0, appare abbastanza spesso in tutti i tipi di calcoli simbolici. 1 è anche comune. Con una singola istanza, SymPy consente due ottimizzazioni. Innanzitutto, salva la memoria. In secondo luogo, è possibile confrontare questi oggetti usando il confronto is, come x is S.One. Perché solo una istanza può mai esistere Integer(1) è sempre la stessa di S.One.

(anche, Vorrei sottolineare che alcuni degli oggetti in S non sono in realtà che comuni, come Catalan e EulerGamma. Credo che sono stati aggiunti più per comodità di ogni altra cosa)

+0

L'auto-wrapping int che rende il collegamento "Esegui il blocco del codice in SymPy Live" per quel particolare gotcha piuttosto sciocco, però. SymPy Live fa l'opposto del comportamento che la documentazione sta cercando di spiegare. – user2357112

+0

Ha un buon punto. Ho aperto https://github.com/sympy/sympy/issues/10484. – asmeurer

Problemi correlati