I have a bit of code that I want to run multiple times. That seams trivial but there is a twist: I want to change the code in a specific way between iterations. For example:
A = 1
B = ['+','-','/'.'*','**']
C = []
for x in range(len(B)):
C.append(A{B[x]}100)
print(C)
Now, I know this code doesn't work and it's not a proper Python syntax, but i't just an example of what I'd like the code to do.
Ideally I'd get C as a list where 0th element is 1 + 100, 1st element is 1 - 100, 2nd element is 1 / 100 etc. (N.b.: NOT '1 + 100' string. A result of 1 + 100 calculation - 101). Basically I want the code to change itself between iterations of loop in a defined way.
I do not want to define some lengthy if/elif statement since list B is very, very long.
Edit:
Let me give another example. This one is more relevant to my problem.
A = ['mom','dad','me','you','c']
B = ['a','b','something','nothing','cat']
for x in range(len(A)):
C_{A[x]} = B[x]
I want to end up with 5 new variables so that:
Print(C_mom)
a
Print(C_dad)
b
Print(C_c)
cat
Again, I recognize this is not a proper python syntax and this code doesn't work.
First create a dict where each string '+','*' etc point to it's corresponding method imported from operator module.
Now loop over B and fetch the corresponding method from the ops dict and pass the operands to the method.
>>> from operator import add,sub,mul,div,pow
>>> ops = {'+':add,'-':sub,'/':div, '*':mul,'**':pow}
>>> B = ['+','-','/','*','**']
>>> A = 1
>>> [ops[item](A,100) for item in B]
[101, -99, 0, 100, 1]
Use '/': operator.truediv if you want ops['/'](1,100) to return 0.01 instead of 0.
Update:
Creating dynamic variables in python is not a good idea, you should better use a dict here:
>>> A = [1,2,3,4,5]
>>> B = ['a','b','something','nothing','cat']
>>> c = {x:y for x,y in zip(A,B)}
>>> c[1]
'a'
>>> c[2]
'b'
>>> c[5]
'cat
Use globals() to create dynamic variables(don't use this method):
for x,y in zip(A,B):
globals()['C'+str(x)] =y
...
>>> C1
'a'
>>> C2
'b'
Related
Hello wonderful people,
I am building a physics model for some project. I have found a nice equation for my interest variable, but I would like to be able to solve the problem repeatedly with different parameters. What I would like to do is to save my equation as an object in a file (using pickle for example), then loading it at runtime and feed it the parameters it needs.
How would you achieve this?
With a simple example, the whole process would look like this:
(in a jupyter notebook)
import sympy as sp
import pickle
a, b, c = symbols("a b c")
eqn = sp.Eq(b + c, a) #for a real equation I would simplify it before using sympy
with open("eqn.txt") as f:
pickle.dump(eqn, f)
and then later in the app's code:
...
with open("eqn.txt") as f:
eqn = pickle.load(f)
b = 1
c = 2
#magic line to put b and c into the equation
a = sp.solve(eqn, a)
print(a) # 3
Implementing the whole equation directly in a function is probably not an option although I am considering how to implement it manually. It just looks really, really hard to do and if I could do it in two lines using simpy, that'd be great.
Thanks for your time!
with open("eqn.txt") as f:
eqn = pickle.load(f)
b, c = 1, 2 # b,c are python symbols here
reps = dict(zip(symbols('b c'), (b, c))) # keys are SymPy Symbols, values are 1,2
eqn = eqn.xreplace(reps) #magic line to put b and c into the equation
a = sp.solve(eqn, a)
print(a) # 3
It is important to keep in mind the distinction between b = 1 and b = Symbol('b'). The left hand side of the expressions are Python variables and on the right, an int or a SymPy Symbol, respectively. In a SymPy expression you might reference a Python variable and its value will be included in the equation:
>>> from sympy import *
>>> b = 1
>>> b + 1
2
>>> b = Symbol('b')
>>> b + 1
b + 1
>>> eq = _
>>> eq.subs(b,1)
2
>>> b=2 # assigning a new value to b does not change the object in eq
>>> eq
b + 1
>>> eq.subs(b, 2) # i.e., eq.subs(2,2) doesn't work -- no 2 in eq
b + 1
>>> eq.subs(Symbol('b'), 2) # replace the Symbol with value of 2 works
3
So in reps above, zipping the symbols to their corresponding values creates a mapping that can be used to do the replacement.
There is more discussion of such issues in the documentation gotchas file, but this should help with your current issue.
Following this logic :
a,b = 0,0
I was expecting this to work :
a,b += 1,1
SyntaxError: illegal expression for augmented assignment
so here i am.
Is there anyway to achieve this in one line ?
Think of it like a list of "how to update each variable" (variables to the left, formulas to the right).
a, b = a+1, b+1
As already mentioned by others, you could combine two statements into one line as a += 1; b += 1.
But, if you prefer a single statement in the same "spirit" as a, b = 0, 0 then try this:
a, b = a + 1, b + 1
The way these assignments work is that a list of variables is assigned a list of values:
variable
value
a
0
b
0
→ a = 0; b = 0 → a, b = 0, 0
variable
value
a
a + 1
b
b + 1
→ a = a + 1; b = b + 1 → a, b = a + 1, b + 1
You can either use multiple statements, one per table row, or a single statement where all the values in the left column go on one side of the = and all the values in the right column go on the other side.
This works only for = though. Your idea a, b += 1 firstly wouldn't work for the same reason a, b = 0 doesn't (there is only one right-hand side value), but a, b += 1, 1 unfortunately also doesn't work, just because Python doesn't support this concept. + with tuples would concatenate them into a larger tuple, not add each of their elements ((1, 2) + (3, 4) is (1, 2, 3, 4) and not (4, 6)).
If you want it in 1 line here is what you can do.. a,b=0 is not the right way , it should have been a=b=0 or a,b=0,0
a=b=0
a+=1;b+=1
You can use map to apply your increment or other operation
a,b=0,0
a, b = map( lambda x : x+1, [a,b])
output
1,1
Is it possible to assign < to a variable, let's say b ?
For example:
b = < .
Edit:
My plan is the following:
a < b < c < d .
I want add the "compares" to a permutation. I know that I can add a b c d to a permutation but I have to change the < too. Please believe me that this is important for my plan. I have to find all possibilities.
You can do it like so
b = '<'
c = '+'
When you want to use it, you have to use the eval function.
eval('5' + b + '10') # '5<10'
>>> True
eval('5' + c + '10') # '5+10'
>>> 15
I tried to run a code in python to remove symbols with index 0, 3, 6, 9... etc. I decided to choose "for" cycle for it. Question: Why does the code not replacing the first symbol?
>>> s = 'Python'
>>> a = len(s)
>>> a
6
>>> for i in range (0, a, 3):
b = s.replace(s[i], '')
>>> b
'Pyton'
>>>
You are overriding b on each iteration. A one liner solution that helps avoiding these mistakes could be:
b = "".join([l for i, l in enumerate(s) if i % 3 != 0])
Example:
In [6]: s = "Python"
In [7]: b = "".join([l for i, l in enumerate(s) if i % 3 != 0])
In [8]: b
Out[8]: 'yton'
If you edit your code to print the variables after every loop, you'll figure out what's happening:
s = 'Python'
a = len(s)
for i in range (0, a, 3):
b = s.replace(s[i], '')
print(i, s, b)
print(">", b)
prints out
0 Python ython
3 Python Pyton
> Pyton
This is because you're assigning to b, but using s as the source replacement string.
You'll get closer by reassigning to s instead:
s = 'Python'
a = len(s)
for i in range (0, a, 3):
s = s.replace(s[i], '')
print(i, s)
print(">", s)
0 ython
3 ythn
> ythn
However note that since you're shortening the string in-place, the indices have changed, and you're not replacing the characters you think you might be. More so if there are multiple instances of the same character, as replace will remove them all.
In each cycle you are overriding the last b.
put a print function inside your loop you will understand.
first you will get ython and the second cycle you will get Pyton.
I have a number of symbolic expressions in sympy, and I may come to realize that one of the coefficients is zero. I would think, perhaps because I am used to mathematica, that the following makes sense:
from sympy import Symbol
x = Symbol('x')
y = Symbol('y')
f = x + y
x = 0
f
Surprisingly, what is returned is x + y. Is there any way, aside from explicitly calling "subs" on every equation, for f to return just y?
I think subs is the only way to do this. It looks like a sympy expression is something unto itself. It does not reference the pieces that made it up. That is f only has the expression x+y, but doesn't know it has any link back to the python objects x and y. Consider the code below:
from sympy import Symbol
x = Symbol('x')
y = Symbol('y')
z = Symbol('z')
f1 = x + y
f2 = z + f1
f1 = f1.subs(x,0)
print(f1)
print(f2)
The output from this is
y
x + y + z
So even though f1 has changed f2 hasn't. To my knowledge subs is the only way to get done what you want.
I don't think there is a way to do that automatically (or at least no without modifying SymPy).
The following question from SymPy's FAQ explains why:
Why doesn't changing one variable change another that depends it?
The short answer is "because it doesn't depend on it." :-) Even though
you are working with equations, you are still working with Python
objects. The equations you are typing use the values present at the
time of creation to "fill in" values, just like regular python
definitions. They are not altered by changes made afterwards. Consider
the following:
>>> a = Symbol('a') # create an object with name 'a' for variable a to point to
>>> b = a + 1; b # create another object that refers to what 'a' refers to
a + 1
>>> a = 4; a # a now points to the literal integer 4, not Symbol('a')
4
>>> b # but b is still pointing at Symbol('a')
a + 1
Changing quantity a does not change b; you are not working with a set
of simultaneous equations. It might be helpful to remember that the
string that gets printed when you print a variable refering to a sympy
object is the string that was give to it when it was created; that
string does not have to be the same as the variable that you assign it
to:
>>> r, t, d = symbols('rate time short_life')
>>> d = r*t; d
rate*time
>>> r=80; t=2; d # we haven't changed d, only r and t
rate*time
>>> d=r*t; d # now d is using the current values of r and t
160
Maybe this is not what you're looking for (as it was already explained by others), but this is my solution to substitute several values at once.
def GlobalSubs(exprNames, varNames, values=[]):
if ( len(values) == 0 ): # Get the values from the
for varName in varNames: # variables when not defined
values.append( eval(varName) ) # as argument.
# End for.
# End if.
for exprName in exprNames: # Create a temp copy
expr = eval(exprName) # of each expression
for i in range(len(varNames)): # and substitute
expr = expr.subs(varNames[i], values[i]) # each variable.
# End for.
yield expr # Return each expression.
# End for.
It works even for matrices!
>>> x, y, h, k = symbols('x, y, h, k')
>>> A = Matrix([[ x, -h],
... [ h, x]])
>>> B = Matrix([[ y, k],
... [-k, y]])
>>> x = 2; y = 4; h = 1; k = 3
>>> A, B = GlobalSubs(['A', 'B'], ['x', 'h', 'y', 'k'])
>>> A
Matrix([
[2, -1],
[1, 2]])
>>> B
Matrix([
[ 4, 3],
[-3, 4]])
But don't try to make a module with this. It won't work. This will only work when the expressions, the variables and the function are defined into the same file, so everything is global for the function and it can access them.