This question is a follow-up of previous question pass class method to fsolve.
#jim's answer in that question about difference between the function object name and a function call clarified my confusion and solved the problem. However, when I tried similar things in sympy:
from sympy.solvers import solve
from sympy import Symbol
class Demo():
def __init__(self, var):
self.i = var
def func(self):
return self.i ** 2 - 4
x = Symbol('x')
def func(v):
return v ** 2 - 4
new = Demo(x)
solve(new.func(), x) # This works fine, even as a function call
solve(func(x), x) # This works fine, even as a function call
Why do I have different results? (In scipy I need to pass function name to solver while in sympy I need to pass the function call.) Is it because different implementation of the two libraries? In the above example, if I substitute the function call with function name, exception will be raised:
File "<ipython-input-26-3554c1f86646>", line 13, in <module>
solve(new.func, x)
File "Anaconda3\lib\site-packages\sympy\solvers\solvers.py", line 817, in solve
f, symbols = (_sympified_list(w) for w in [f, symbols])
File "Anaconda3\lib\site-packages\sympy\solvers\solvers.py", line 817, in <genexpr>
f, symbols = (_sympified_list(w) for w in [f, symbols])
File "Anaconda3\lib\site-packages\sympy\solvers\solvers.py", line 808, in _sympified_list
return list(map(sympify, w if iterable(w) else [w]))
File "Anaconda3\lib\site-packages\sympy\core\sympify.py", line 324, in sympify
raise SympifyError('could not parse %r' % a, exc)
SympifyError: Sympify of expression 'could not parse '<bound method Demo.func of <__main__.Demo object at 0x0000018A37DA6518>>'' failed, because of exception being raised:
SyntaxError: invalid syntax (<string>, line 1)
When the solver is provided parameter (func(x), x), it is equivalent to provide (x ** 2 - 4, x), the first part of which is an expression containing the declared symbol x.
However when the parameter list is (func, x), the variable in function definition, v, is undefined and does not match that provided as the second argument, which is x. This causes exception to be raised.
In the scipy case, returned expression of the function definition has one variable, var, to be solved, and can thus work properly.
Related
Below code I have.
from sympy import *
x = symbols('x')
expr = sin(x)
# Use sympy.lambdify() method
f = lambdify(x, expr, "math")
If print(f) its giving '<function _lambdifygenerated at 0x100d643a0>', is there any way to get back the expression(sin(x)) from f?
help(f) displays:
Help on function _lambdifygenerated:
_lambdifygenerated(x)
Created with lambdify. Signature:
func(x)
Expression:
sin(x)
Source code:
def _lambdifygenerated(x):
return sin(x)
f.__doc__ is the same string.
Since we specified 'math', scalars work, but not arrays:
In [12]: f(1.23)
Out[12]: 0.9424888019316975
In [13]: f(np.arange(3))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Input In [13], in <module>
----> 1 f(np.arange(3))
File <lambdifygenerated-2>:2, in _lambdifygenerated(x)
1 def _lambdifygenerated(x):
----> 2 return sin(x)
TypeError: only size-1 arrays can be converted to Python scalars
I have gone into the source code of Sympy and found this line where the content of the lambdified function is defined in the variable funcstr:
https://github.com/sympy/sympy/blob/88b9cba9d7e633ec769baf1fc5267acfd7f54788/sympy/utilities/lambdify.py#L863
# Create the function definition code and execute it
funcname = '_lambdifygenerated'
if _module_present('tensorflow', namespaces):
funcprinter = _TensorflowEvaluatorPrinter(printer, dummify) # type: _EvaluatorPrinter
else:
funcprinter = _EvaluatorPrinter(printer, dummify)
if cse == True:
from sympy.simplify.cse_main import cse as _cse
cses, _expr = _cse(expr, list=False)
elif callable(cse):
cses, _expr = cse(expr)
else:
cses, _expr = (), expr
funcstr = funcprinter.doprint(funcname, iterable_args, _expr, cses=cses)
Currently Sympy does not return funcstr, but I modified it in my local installation so that it does, and it seems to be what you are after.
import sympy as sy
x = sy.symbols('x')
expr = sy.sin(x)
# Use sympy.lambdify() method
f, funcstr = sy.lambdify(x, expr, "math")
funcstr.split(":")[-1].split("return")[-1].strip()
>>> 'sin(x)'
The way I got the content out is a bit dodgy, and not necessarily robust, but I hope it gives you a starting point to work with.
Beware that if you used the argument cse, this extraction will not be accurate, since it will miss out on the previous simplifications.
I have defined the following functions
def f(x):
return x*a
def g(x,a):
return f(x)
g(1,2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in g
File "<stdin>", line 2, in f
NameError: name 'a' is not defined
Now if I try to evaluate g(x,a) for any value of x and a it states that a is not defined. I suspect this is because a should be a global variable.
I have heard that using global variables is bad practice so my question is how do I make g(x,a) give a result with a given as an argument?
Note: The reason I am not giving a as an argument to f(x) is because it needs to be solved as a differential equation (using scipy) with only the relevant variables as arguments.
Since a is a variable within the function g, why not avoid the entire global situation by the following:
def f(x):
# do something to alter x
return x
def g(x, a):
return f(x)*a
g(1,2) # returns f(x) *2
I came across this error
def test_rec():
import ast
exec(compile(ast.fix_missing_locations(ast.parse("""
def fact(n):
return 1 if n == 0 else n * fact(n - 1)
print(fact(5))
"""), "<string>", "exec")))
This yield this error, which is weird
Traceback (most recent call last):
File "/Users/gecko/.pyenv/versions/3.9.0/envs/lampy/lib/python3.9/site-packages/nose/case.py", line 198, in runTest
self.test(*self.arg)
File "/Users/gecko/code/lampycode/tests/test_let_lang.py", line 6, in test_rec
exec(compile(ast.fix_missing_locations(ast.parse("""
File "<string>", line 4, in <module>
File "<string>", line 3, in fact
NameError: name 'fact' is not defined
If I copy and paste the same code in REPL it works fine
>>> def fact(n):
... return 1 if n == 0 else n * fact(n - 1)
...
>>> print(fact(5))
120
>>>
Any ideas?
I could reduce the problem further here is the minimal exempla, this would overflow the stack but it gives me the same not defined error
def test_rec3():
exec("""
def f():
f()
f()
""")
--
Second edit, going even further, this only happens inside functions
This works
exec("""
def f(n):
print("end") if n == 1 else f(n-1)
f(10)""")
But this gives me the same error as above
def foo():
exec("""
def f(n):
print("end") if n == 1 else f(n-1)
f(10)""")
foo()
If you use exec with the default locals, then binding local variables is undefined behavior. That includes def, which binds the new function to a local variable.
Also, functions defined inside exec can't access closure variables, which fact would be.
The best way to avoid these problems is to not use exec. The second best way is to provide an explicit namespace:
namespace = {}
exec(whatever, namespace)
In python3, if a function with recursive invoking is injected into exec() in a function, I got an error.
For example, below code
def B(pys):
exec(pys)
pys="""
def fibonacci(n):
if n == 1 or n == 2:
r = 1
else:
r = fibonacci(n - 1) + fibonacci(n - 2)
return r
print(fibonacci(3))
"""
B(pys)
will raise NameError.
$ py -3.8 testrecursivefun.py
Traceback (most recent call last):
File "testrecursivefun.py", line 14, in <module>
B(pys)
File "testrecursivefun.py", line 2, in B
exec(pys)
File "<string>", line 9, in <module>
File "<string>", line 6, in fibonacci
NameError: name 'fibonacci' is not defined
If I run exec(pys) directly under the module, the exception disappeared.
The reason has been described in another question How does exec work with locals?. But I still don't know how I can figure out the recursive invoking in exec(). Because the function name is dynamic for me. I cannot add it to locals() to exec(). Who can help me figure it out.
For the sake of an answer, you can wrap your code in a function so the recursive function is in its local scope:
import textwrap
def B(pys):
exec(pys, globals(), {})
pys="""
def fibonacci(n):
if n == 1 or n == 2:
r = 1
else:
r = fibonacci(n - 1) + fibonacci(n - 2)
return r
print(fibonacci(11))
"""
def wrap(s):
return "def foo():\n" \
"{}\n" \
"foo()".format(textwrap.indent(s, ' ' * 4))
B(wrap(pys))
Generally, reconsider using exec.
I actually got interested in your question, so I started researching on this topic. Seems like the simple solution to your problem is to:
First compile the string to code using compile function in python
Then execute the compiled code using exec function
Here is the sample solution:
psy="""
def fibonacci(n):
if n == 1 or n == 2:
r = 1
else:
r = fibonacci(n - 1) + fibonacci(n - 2)
return r
print(fibonacci(3))
"""
def B(psy):
code = compile(psy, '<string>', 'exec')
exec(code, globals())
B(psy)
Here compile takes three parameters:
First is the code in string format, Second is the filename hint which we used as we take string as code itself, and third can be one of 'exec', 'eval' and 'single'.
This link contains detail explanation of how you should use exec and eval in python. Do check them out for detail explanation.
Consider the Python function line defined as follows:
def line(m, b):
def inner_function(x):
return m * x + b
return inner_function
This function has the property that for any floats m and b, the object line(m, b) is a Python function, and when line(m, b) is called on a float x, it returns a float line(m, b)(x). The float line(m, b)(x) can be interpreted as the value of the line with slope m and y-intercept b at the point x. This is one method for writing a Python function that "depends on parameters" m and b.
Is there a special name for this method of writing a Python function that depends on some parameters?
Is there a more Pythonic and/or computationally efficient way to write a function that does the same thing as line above?
This is called a closure, and it's a perfectly reasonable way to write one, as well as one of the most efficient means of doing so (in the CPython reference interpreter anyway).
The only other common pattern I know of is the equivalent of C++'s functors, where a class has the state as attributes, and the additional parameters are passed to __call__, e.g. to match your case:
class Line:
def __init__(self, m, b):
self.m = m
self.b = b
def __call__(self, x):
return self.m * x + self.b
It's used identically, either creating/storing an instance and reusing it, or as in your example, creating it, using it once, and throwing it away (Line(m, b)(x)). Functors are slower than closures though (as attribute access is more expensive than reading from nested scope, at least in the CPython reference interpreter), and as you can see, they're more verbose as well, so I'd generally recommend the closure unless your needs require the greater flexibility/power of class instances.
I support #ShaddowRanger's answer. But using partial is another nice approach.
import functools
def f(m, b, x):
return m * x + b
line = functools.partial(f, 2, 3)
line(5)
=> 13
One thing which is worth pointing out is that lambda objects, and OP's inner_function aren't pickleable, whereas line here, as well as #ShaddowRanger's Line objects are, which makes them a bit more useful.
This is a little shorter:
def line(m,b):
return lambda x: m*x+b;