how to set .__name__ in python? - python

I am trying to solve this exercise:
Return a function that represents the polynomial with these
coefficients.
For example, if coefs=(10, 20, 30), return the function of x that computes
30 * x**2 + 20 * x + 10. Also store the coefs on the .coefs attribute of
the function, and the str of the formula on the .__name__ attribute.
This is my solution:
def poly(coefs):
#write the string name
l=len(coefs)
coefs=reversed(coefs)
j=0
name=""
for i in coefs:
if j<l-2:
name=name+str(i)+" * x**"+str(l-j-1)+" + "
elif j==l-2:
name=name+str(i)+" * x + "
else:
name=name+str(i)
j=j+1
def calc(x):
name.replace("x",str(x))
calc.__name__=name
return eval(name)
return calc
It does not work very well.
>>> p=poly((1,2,3))
>>> p
<function calc at 0x3b99938> #the name of p is not what I want!!! (*)
>>> y=p(3)
>>> p
<function 3 * x**2 + 2 * x + 1 at 0x3b99938> # now this is right!
>>>
How can I have the right name also in the first call (*) ?

Set the name outside of the function object:
def calc(x):
newname = name.replace("x", str(x))
calc.__name__ = newname
return eval(name)
calc.__name__ = name
return calc
Note that str.replace() does not replace values in strings in-place. It returns the altered string, string values themselves are immutable.
Your initial name will have to use x, since the value of x is not known at the time you call poly(). I'd leave out filling in of x in the name however; the function will not return that exact calculation the next time you call it with a different x. Without replacing x in the name each time you call the function, calc() would simply be:
def calc(x):
return eval(name)
Together with adding name = '' at the top of your poly() function, with the namechange per call in place still, gives:
>>> p = poly((1,2,3))
>>> p
<function 3 * x**2 + 2 * x + 1 at 0x10ecf5488>
>>> p(3)
34
>>> p
<function 3 * 3**2 + 2 * 3 + 1 at 0x10ecf5488>

Related

How to pass a function as an argument

I would like to find an approximate value for the number pi = 3.14.. by using the Newton method. In order to use it also for some other purpose and thus other function than sin(x), the aim is to implement a generic function that will be passed over as an argument. I have an issue in passing a function as an argument into an other function. I also tried lambda in different variations. The code I am showing below produces the error message: IndexError: list index out of range. I will appreciate your help in solving this issue and eventually make any suggestion in the code which may not be correct. Thanks.
from sympy import *
import numpy as np
import math
x = Symbol('x')
# find the derivative of f
def deriv(f,x):
h = 1e-5
return (lambda x: (f(x+h)-f(x))/h)
def newton(x0,f,err):
A = [x0]
n = 1
while abs(A[n]-A[n-1])<=err:
if n == 1:
y = lambda x0: (math.f(x0))
b = x0-y(x0)/(deriv(y,x0))
A.append(b)
n += 1
else:
k = len(A)
xk = A[k]
y = lambda xk: (math.f(xk))
b = newton(A[k],y,err)-y(newton(A[k],y,err))/deriv(y,k)
A.append(b)
n += 1
return A, A[-1]
print(newton(3,math.sin(3),0.000001))
I don't know why you use sympy because I made it without Symbol
At the beginning you have to calculate second value and append it to list A and later you can calculate abs(A[n]-A[n-1]) (or the same without n: abs(A[-1] - A[-2])) because it needs two values from this list.
Other problem is that it has to check > instead of <=.
If you want to send function sin(x) then you have to use math.sin without () and arguments.
If you want to send function sin(3*x) then you would have to use lambda x: math.sin(3*x)
import math
def deriv(f, x, h=1e-5):
return (f(x+h) - f(x)) / h
def newton(x0, f, err):
A = [x0]
x = A[-1] # get last value
b = x - (f(x) / deriv(f, x)) # calculate new value
A.append(b) # add to list
while abs(A[-1] - A[-2]) > err: # it has to be `>` instead of `<=`
x = A[-1] # get last value
b = x - (f(x) / deriv(f, x)) # calculate new value
A.append(b) # add to list
return A, A[-1]
# sin(x)
print(newton(3, math.sin, 0.000001)) # it needs function's name without `()`
# sin(3*x)
print(newton(3, lambda x:math.sin(3*x), 0.000001))
# sin(3*x) # the same without `lambda`
def function(x):
return math.sin(3*x)
print(newton(3, function, 0.000001))
Result:
([3, 3.1425464414785056, 3.1415926532960112, 3.141592653589793], 3.141592653589793)
([3, 3.150770863559604, 3.1415903295877707, 3.1415926535897936, 3.141592653589793], 3.141592653589793)
EDIT:
You may write loop in newton in different way and it will need <=
def newton(x0, f, err):
A = [x0]
while True:
x = A[-1] # get last value
b = x - (f(x) / deriv(f, x)) # calculate new value
A.append(b) # add to list
if abs(A[-1] - A[-2]) <= err:
break
return A, A[-1]

How can i change a variable name in a sympy expression

I am working on a project where I need to change all variables that are named 'a' to a new variable ai, where i is the order of the variable a in the expression. For instance if we use the expression: 1 + x + a + a ** 2, the output should be: 1 + x + a0 + a1 ** 2. Here is a code that I've written to solve this but it doesn't work, the expression remains unchanged.
import sympy.parsing.sympy_parser as sp1
import sympy as sp
I=sp1.parse_expr('1 + x + a + a**2', evaluate=False)
a,x=sp.symbols('a x')
def pre(expr):
i=0
for arg in sp.postorder_traversal(expr):
if arg==a:
tmp=sp.symbols('a'+str(i))
arg=tmp
print(arg)
i=i+1
pre(I)
print(I)
One way to achieve that is:
from sympy import Pow, Mul, Symbol, degree
def change_symbol(expr, a):
"""expr: the expression to modify
a: the symbol to look for and substitute
"""
# define a wild symbol to look for Symbols, Multiplications and Powers
# containing the specified symbol
w = Wild("w", properties=[
lambda t: isinstance(t, (Pow, Mul, Symbol)) and ((a in t.args) or (t == a))
])
# find the terms that satisfy the above criteria
terms = list(expr.find(w))
terms.sort(key=lambda t: degree(t), reverse=True)
# loop over those terms and performs the substitution with new symbols
name = a.name
for t in terms:
o = degree(t)
s = Symbol(name + "%s" % (o - 1))
expr = expr.subs(t, s**o)
return expr
change_symbol(I, a)
# out: a0 + a1**2 + x + 1
Your code did not work because you never changed the expression. When you say arg = tmp that assigns a value of tmp to arg but this does not update expr. #Davide_sd shows a way to recreate an expression with pieces that have been modified. You can also let replace do the traversal and let it replace a as it encounters it.
suffix = [0] #mutable suffix
def na():
rv = Symbol('a%s'%suffix[0])
suffix[0]+=1 # modify for next time
return rv
>>> a,x=var('a x')
>>> (1 + x + 2*a + a**2).replace(lambda x: x==a, lambda x: na())
a0**2 + 2*a1 + x + 1
Note that you said "order in expression" and coded as though you meant "order encountered" but in the polynomial sense, "higher order" terms will not necessarily appear later in the ordered terms. Note that a**2 appears before 2*a and that is why the replace gave it a value of a0:
>>> (1 + x + 2*a + a**2).args
(1, x, a**2, 2*a)

Why does my lambdify not working when add my own function

I created a function and make it usable in my Sympy expression like this:
def Unit(x):
if(x != 0):
return 0
else:
return 1
Unit = Function('Unit')
x = Symbol('x')
My expression:
fx = x ** 2 + Unit(x)
But when I run:
lam_f = lambdify(x, fx, modules=["sympy"])
print(lam_f(-1))
It said that my Unit is not defined?
Can anyone explain where i went wrong?
Function('Unit') returns an undefined function with name Unit. See this question. If you want to use your previously defined function Unit, remove the call to Function():
def Unit(x):
if(x != 0):
return 0
else:
return 1
x = Symbol('x')
fx = x**2 + Unit(x)
lam_f = lambdify(x, fx, modules=['sympy'])
print(lam_f(-1)) # prints 1

python - enter the correct number of variables based on function handle

I have a list of variables, and a function object and I would like to assign the correct number of variable depending on the function.
def sum2(x,y):
return x + y
def sum3(x,y,z):
return x + y + z
varList = [1,2,3]
so if f = sum2 , I would like it to call first 2 elements of varList, and if f = sum3 , to call it with 3 elements of the function.
This can be done in a single function, if you are always returning the sum of all the passed arguments.
def sum1(*args):
return sum(args)
This is just utilizing positional arguments, as you don't appear to need to explicitly set individual values. It is also most flexible than the solution provided by ZdaR, as you don't need to know ahead of time the maximum number of arguments you can receive.
Some examples:
>>> print sum1(1, 2, 3)
6
>>> print sum1(1)
1
>>> print sum1(-1, 0, 6, 10)
15
Use the inspect module as follows:
import inspect
n2 = len(inspect.getargspec(sum2)[0])
n3 = len(inspect.getargspec(sum3)[0])
sum2(*varList[0:n2])
sum3(*varList[0:n3])
getargspec returns a 4-tuple of (args, varargs, keywords, defaults). So the above code works if all your args are explicit, i.e. not * or ** args. If you have some of those, change the code accordingly.
You may use default initialization, You should keep in mind the maximum number of variables that could be passed to this function. Then create a function with that number of parameters but initializing them with 0, because a+0 = a(in case some parameters are missing it will replace then with 0 which won't affect the results.)
def sum1(a=0, b=0, c=0, d=0):
return a+b+c+d
print sum1(1)
>>> 1
print sum1(1, 2)
>>> 3
print sum1(1, 2, 3)
>>> 6
print sum1(1, 2, 3, 4)
>>> 10
However, if you call the function with more than 4 arguments, it would raise error statement
Also as suggested by #CoryKramer in the comments you can also pass your varlist = [1, 2, 3, 4] as a parameter :
print sum1(*varlist)
>>> 10
Keeping in mind that the len(varlist) should be less than the number of parameters defined.
A general solution:
To get the number of argument, you can use f.func_code.co_argcount and than pass the correct elements from the list:
def sum2(x,y):
return x + y
def sum3(x,y,z):
return x + y + z
varlist = [2,5,4]
[f(*varlist[:f.func_code.co_argcount]) for f in [sum2,sum3]]
>> [7, 11]
You can check if f is a function with the is keyword
def sum2(x, y):
return x + y
def sum3(x, y, z):
return x + y + z
varList = [1, 2, 3]
f = sum2
if f is sum2:
sum = f(varList[0], varList[1])
print('Sum 2: ' + str(sum))
# Prints: 'Sum 2: 3'
f = sum3
if f is sum3:
sum = f(varList[0], varList[1], varList[2])
print('Sum 3: ' + str(sum))
# Prints: 'Sum 3: 6'
A dict of functions:
def two(l):
return l[0] + l[1]
def three(l):
return l[0] * l[1] + l[2]
funcs = {2:two, 3:three}
l = [1, 2, 3]
print len(l)
print funcs[len(l)](l)

Python: function arguments and return values

Say I have a function
def equals_to(x,y):
a + b = c
def some_function(something):
for i in something:
...
Is there a way to use c that was calculated by equals_to as a parameter for some_function like this
equals_to(1,2)
some_function(c)
You need to return the value of c from the function.
def equals_to(x,y):
c = x + y # c = x + y not a + b = c
return c # return the value of c
def some_function(something):
for i in something:
...
return
sum = equals_to(1,2) # set sum to the return value from the function
some_function(sum) # pass sum to some_function
Also the function signature of equals_to takes the arguments x,y but in the function you use a,b and your assignment was the wrong way round, c takes the value of x + y not a + b equals c.
Strongly recommend: http://docs.python.org/2/tutorial/

Categories

Resources