Python specifying function as input [duplicate] - python

This question already has answers here:
how to define a function from a string using python
(4 answers)
Closed 4 years ago.
import math
def g(x):
return x**2+3
def Integrate(f, a , b, n):
h=(b-a)/n
result=0
for k in range(n):
x=k*h+h/2
result+=f(x)*h
return result
F=input("f:")
A=float(input("a:"))
B=float(input("b:"))
N=int(input("n:"))
print(Integrate(F, A, B, N))
Whenever i try to run this code, it reads F to be a string and gives an error when called in integrate(f, a, b, n). I found that there is no way in python to define F as a function, but calling a function in another function is definitely possible. Then how can i still pull this way of using an input to specify what function to use off?
error:
line 14, in Integrate
result+=f(x)*h
TypeError: 'str' object is not callable

You can input a function on the console by using a lambda (as a string), and use eval to convert the string to an actual function object. Your code would look like this:
F = eval(input("f:"))
On the console, if you want to integrate the function f(x) = 2 * x + 1, you'd input:
lambda x: 2 * x + 1
as a string. However, note that eval will execute (as Python code) whatever you input on the console, and this could be a security concern depending on how your program is used.

I don't know if you want to use function from math module, but if yes then you can obtain method from module by string like this:
function_to_call = getattr(math, f)
result += function_to_call(x) * h
When doing this you should surround with try except block to check if given function name exit in math module.

Related

How can I get the function object inside a lambda function

Sorry if this is very lame, but I'm pretty new to Python.
As in Python everything is an object, I assume in every object the object itself can be get somehow. In object methods the self variable contains it. From the object reference the class object can be get (like type(self)). But how this could be got inside a lambda?
I could figure out for a normal function:
import inspect
def named_func():
func_name = inspect.stack()[0].function
func_obj = inspect.stack()[1].frame.f_locals[func_name]
print(func_name, func_obj, func_obj.xxx)
named_func.xxx = 15
named_func()
The output looks like this:
named_func <function named_func at 0x7f56e368c2f0> 15
Unfortunately in a lambda the inspect.stack()[0].function gives <lambda> inside the lambda.
Is there a way to get the function object inside a lambda?
Is there a way to get function object directly (not using the name of the function)?
I imagined __self__, but it does not work.
UPDATE
I tried something like this in lambda:
lambda_func = lambda : inspect.stack()[0]
lambda_func.xxx = 2
print(lambda_func())
This prints:
FrameInfo(frame=<frame at 0x7f3eee8a6378, file './test_obj.py', line 74, code <lambda>>, filename='./test_obj.py', lineno=74, function='<lambda>', code_context=['lambda_func = lambda : inspect.stack()[0]\n'], index=0)
But for example is there a way to get the lambda object field xxx in this case? For this the lambda object should be got somehow.
We can now use a new python syntax to make it shorter and easier to read, without the need to define a new function for this purpose.
You can find two examples below:
Fibonacci:
(f:=lambda x: 1 if x <= 1 else f(x - 1) + f(x - 2))(5)
Factorial:
(f:=lambda x: 1 if x == 0 else x*f(x - 1))(5)
We use := to name the lambda: use the name directly in the lambda itself and call it right away as an anonymous function.
So in your particular use-case it would give something like that:
print((f:=lambda: f.__hash__())()) # prints the hash for example
You can do whatever you want with that f variable now (inside the lambda).
But in fact, if you don't mind multi-lines for your code, you could also just use the name directly and do something like that:
f = lambda : f.xxx
f.xxx = 2
print(f())
(see https://www.python.org/dev/peps/pep-0572 for more information about this := operator)
Note, this is not an efficient/pragmatic solution to the problem. This is not a recommendation about how to write actual software.. it simply presents how access to the lambda reference from the lambda can be achieved without assigning it to a variable name. This is a very hacky answer.
This will only work completely correctly if you follow the advice from the answer found here
In short, given the stack you can find the code object, and then using the gc module you can find the reference to your lambda.
Example with #Tomalak's factorial lambda!
import gc
import inspect
def current_lambda():
lambda_code = inspect.stack()[1].frame.f_code
candidates = [
referrer
for referrer in gc.get_referrers(lambda_code)
if inspect.isfunction(referrer)
and referrer.__code__ is lambda_code
]
if len(candidates) != 1:
raise ValueError(
"Multiple candidates found! Cannot determine correct function!"
)
return candidates[0]
print((lambda n: 1 if n < 2 else n * current_lambda()(n - 1))(5))
Outputs
120
Revisiting your example:
lambda_func = lambda: current_lambda().xxx
lambda_func.xxx = 10
print(lambda_func())
Outputs:
10

How can I add a f(x) as an argument on Python function?

I'm trying to find the maximum of any function f(x) in a certain range and in which x this happens. The arguments of the python function would be (f(x),[a,b]). f(x) being any function and [a,b] the range we will be studying.
For now I've tried a few things but none of them worked. The one I liked the most was a failure because of trying to convert a string onto a float.
def maxf(function,interval):
maxresult = 0
for x in range(interval[0]-1,interval[1]+1):
result=float(function.replace("x",str(x)))
if result >= maxresult:
maxresult = result
maxresultx = x
return maxresult,maxresultx
print(maxf("x**2",[1,3]))
This one returns:
Traceback (most recent call last):
File "main.py", line 10, in <module>
print(maxf("x**2",[1,3]))
File "main.py", line 4, in maxf
result=float(function.replace("x",str(x)))
ValueError: could not convert string to float: '0**2'
I don't know if there is an easier way to do it or how to correct the code so that I can convert that string.
Your problem is that float() accepts a string that already represents a float (eg float("1.23"), not an expression that will result in one (eg float("2**3")). So, you must first evaluate the string.
float(eval("3**2"))
eval() will run any code contained in the string, so don't use it on code you don't trust.
Use this:
def maxf(function,interval):
maxresult = 0
for x in range(interval[0]-1,interval[1]+1):
result=float(function(x))
if result >= maxresult:
maxresult = result
maxresultx = x
return maxresult,maxresultx
print(maxf(lambda x: x**2,[1,3]))
lambda defines a function (an anonymous one) that is passed as parameter, thus maxf can call it as needed.
Python is (also) a functional language, which means that you can use functions as you use ints or floats, etc. A function is just a bunch of callable code, you can associate an identifier to a function or not (just like int values referred by identifiers or as constant in code).
-----EDIT----- suggested by #bacjist
If you don't want to use lambda, then you may define the function as usual:
def f(x):
return x**2
and then call:
print(maxf(f,[1,3]))
The problem is your string is not actually being evaluated. It is just being converted to float so as the error suggests what you are doing is converting "0**2" to float which is not possible what you can do is make use of eval function to evaluate any given string and then compare the result.
You just need to make a small change like this:
result=eval(function.replace("x",str(x)))
This yet not the best way to do this you should use generator there:
def maxf(function,interval):
maxresult = 0
for x in range(interval[0]-1,interval[1]+1):
yield eval(function.replace("x",str(x))), x
print(max(maxf("x**2", [1, 3])))
A more pythonic approach would be using lambda with max function as a key
a_list = [1,3]
max_item = max(a_list, key=lambda x: eval("x**2"))
print(eval("x**2".replace("x", str(max_item))), max_item)

Python TypeError: multiple arguments with functools.partial [duplicate]

This question already has answers here:
functools.partial wants to use a positional argument as a keyword argument
(3 answers)
Closed 4 years ago.
I ran into an error when using partial from the functools library.
from functools import partial
def add(x,a,b):
return x + 10*a + 100*b
add = partial(add, x=2, b=3)
print (add(4))
I get the error:
TypeError: add() got multiple values for argument 'x'
I know that this can be fixed by bringing forward a to the first positional argument of add like:
def add(b,a,x):
return x + 10*a + 100*b
add = partial(add, x=2, a=3)
print (add(4))
which correctly gives out: 432
My question is whether there is a way to keep the order of x,a,b intact within the add function and altering the partial function to give out the correct result. This is important because something like the add function is used elsewhere and so it is important for me to keep the order in the original add function intact.
I don't want to use a keyword argument with the function like print (add(a = 4)) because I want it as an input to a map function
For example I want to do something like this:
print (list(map(add,[1,2,3])))
print (min([1,2,3], key = add)))
The only way to resolve you issue is to use keyword arguments with this function like so
print (add(b=4))
Because using it like this print (add(4)) assigns it to first parameter which partial already defined so x is passed twice
EDIT
You can also use partial with positional arguments
like so:
from functools import partial
def add(x, a, b):
return x + 10 * a + 100 * b
add = partial(add, 2, 3)
print(add(4))
The second solution is possible because x and a are the first two parameters. The approach with keyword arguments is used when you do not want define consecutive parameters starting from the first.

iterative definition of functions in Python [duplicate]

This question already has answers here:
True dynamic and anonymous functions possible in Python?
(8 answers)
Closed 6 years ago.
I am getting crazy with this kind of problem:
I have a list of string representing functions (for eval), I need first to replace the variables with generic x[0], x[1],....
Some time ago I discovered that I can do this using subs(). Then I need to generate a list of functions (to define constraints in SciPy minimize).
I am trying something like:
el=[budget.v.values()[0],silly.v.values()[0]] # my list of string/equations
fl=[]
for i in range(len(el)):
def sos(v):
vdict = dict(zip(q.v.values(),v))
return eval(el[i]).subs(vdict)
fl.append(sos)
del sos # this may be unnecessary
The result for fl is:
[<function sos at 0x19a26aa28>, <function sos at 0x199e3f398>]
but the two functions always give the same result (corresponding to the last 'sos' definition). How can I retain different function definitions?
Your comment:
but the two functions always give the same result (corresponding to the last 'sos' definition)
Is a big clue that you've likely run into this common gotcha!
Your code isn't in a runnable form so I can't verify this but it clearly has this bug. There are various ways to fix this including using functools.partial as explained in the first link.
For example (untested as your code isn't runnable as-is):
import functools
for i in range(len(el)):
def sos(i, v):
vdict = dict(zip(q.v.values(),v))
return eval(el[i]).subs(vdict)
fl.append(functools.partial(sos, i))
Given this you can now refactor this code to avoid redefining the function inside the loop:
def sos(i, v):
vdict = dict(zip([2], v))
return eval(el[i]).subs(vdict)
for i in range(len(el)):
fl.append(functools.partial(sos, i))
To give you a complete and runnable example:
import functools
def add_x(x, v):
return x + v
add_5 = functools.partial(add_x, 5)
print add_5(1)
Produces:
6

Python function handle ala Matlab

In MATLAB it is possible to create function handles with something like
myfun=#(arglist)body
This way you can create functions on the go without having to create M-files.
Is there an equivalent way in Python to declare functions and variables in one line and to call them later?
Python's lambda functions are somewhat similar:
In [1]: fn = lambda x: x**2 + 3*x - 4
In [2]: fn(3)
Out[2]: 14
However, you can achieve similar effects by simply defining fn() as a function:
In [1]: def fn(x):
...: return x**2 + 3*x - 4
...:
In [2]: fn(4)
Out[2]: 24
"Normal" (as opposed to lambda) functions are more flexible in that they allow conditional statements, loops etc.
There's no requirement to place functions inside dedicated files or anything else of that nature.
Lastly, functions in Python are first-class objects. This means, among other things, that you can pass them as arguments into other functions. This applies to both types of functions shown above.
This is not quite the full answer. In matlab, one can make a file called funct.m:
function funct(a,b)
disp(a*b)
end
At the command line:
>> funct(2,3)
6
Then, one can create a function handle such as:
>> myfunct = #(b)funct(10,b))
Then one can do:
>> myfunct(3)
30
A full answer would tell how to do this in python.
Here is how to do it:
def funct(a,b):
print(a*b)
Then:
myfunct = lambda b: funct(10,b)
Finally:
>>> myfunct(3)
30
Turns out there is something that goes all the way back to 2.5 called function partials that are pretty much the exact analogy to function handles.
from functools import partial
def myfun(*args, first="first default", second="second default", third="third default"):
for arg in args:
print(arg)
print("first: " + str(first))
print("second: " + str(second))
print("third: " + str(third))
mypart = partial(myfun, 1, 2, 3, first="partial first")
mypart(4, 5, second="new second")
1
2
3
4
5
first: partial first
second: new second
third: third default

Categories

Resources