F.N.B
F.N.B

Reputation: 1619

Functions in SymPy

I am new to Python objects and have a lot of questions. I need to pass a function to my object, and then evaluate the function. The code is similar to this:

from sympy import var

class eval:
    def __init__(self, M):
        self.M = M

    def fun(self, x):
        M = self.M
        print M(x)

x = var('x')

ak = eval(x+2)
ak.fun(x)

This is the error:

TypeError
Traceback (most recent call last)
(ipython-input-1-b7ef311bd1f0> in <module)()
     12 
     13 ak = eval(x+2)
---> 14 ak.fun(x)

(ipython-input-1-b7ef311bd1f0) in fun(self, x)
      7     def fun(self, x):
      8         M = self.M
----> 9         print M(x)
     10 
     11 x = var('x')

TypeError: 'Add' object is not callable

Upvotes: 2

Views: 7812

Answers (3)

Krastanov
Krastanov

Reputation: 6549

I am new to Python objects...

Having questions is great, but the objects and classes behind SymPy are quite complex and learning the basics of the Python object model before delving in such a library is strongly encouraged.

There are many issues with the suggested code:

Purely language related errors

  • eval is build-in so it is bad style to overwrite it
  • using old-style classes

Using SymPy as if it is some language extension

SymPy does not provide new syntax for creating python functions. Especially, (x+2)(4) is not going to give you 6. If you want this just write myfun = lambda _: _+2; fun(4) without using SymPy.

x+2 is a SymPy object (Add(Symbol('x')+Integer(2))), not some python AST. You can substitute x for something else with (x+2).subs(x,y) but you can not expect the library to magically know that you have something special in mind for Symbol('x') when you write (x+2)(4). You can as well write blah = Symbol('random_string'); (blah+2)(4).

Minor SymPy errors

var is a helper function used to create Symbol objects, but it is meant for interactive use in the interpreter. Do not use it in library code because as a side effect it injects global variables in the namespace. Just use Symbol('x').

Now about x+2 being callable

In 0.7.2 recursive calling was implemented. What this means is that you can create a SymPy Expr tree that contains unevaluated symbolic objects and apply the whole tree on another object, the calls propagating inwards until all unevaluated objects are substituted with evaluated ones. I guess the above description is not clear so here is an example:

You want to create a differential operator object D which can do the following:

>>> op = g(y)*D # where g is Function and y is Symbol
>>> op(f(x))
g(y)*f(x).diff(x)

The way this works is to go down the tree (Mul(g(y), D) in this case), skip evaluated symbolic objects and evaluate unevaluated symbolic objects.

Because a lot of SymPy's users start using it before reading about the data model this caused a lot of confusion, so we moved the recursive calling scheme to the rc method. In 0.7.3 (x+2)(4) will raise errors again.

Upvotes: 10

jfs
jfs

Reputation: 414835

Your code already can pass a function to the object. Functions are first-class citizens in Python you can pass them as any other object. The issue might be with your sympy version. Compare:

>>> import sympy
>>> sympy.__version__
'0.7.1.rc1'
>>> from sympy.abc import x
>>> (x + 2)(x)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: 'Add' object is not callable

And:

>>> import sympy
>>> sympy.__version__
'0.7.2'
>>> from sympy.abc import x
>>> (x + 2)(x)
x + 2

i.e., the same code works on 0.7.2 but it fails on 0.7.1rc1 version.

Upvotes: 1

rh0dium
rh0dium

Reputation: 7052

There is couple issues with this.

  • You don't define the class as an object
  • You named the function eval which is a reserved word

Try this:

class Eval(object):
    def __init__(self,m):
        self.M = m

    def fun(self,x):
        print self.M(x)

x = var('x')
ak = Eval(x+2)
ak.meth(x)
x + 2

HTH

Upvotes: 1

Related Questions