How to understand this simultaneous assignment evaluation in python 3? [duplicate] - python-3.x

This question already has answers here:
Multiple assignment and evaluation order in Python
(11 answers)
Closed 3 years ago.
I have recently started learning python. I was playing around with simultaneous assignments today and came across some results that were produced by my code that I cannot understand.
x, y = 3, 5
x, y = y, (x+y)
print(y)
The output is 8.
I am not understanding why y = 8 instead of y = 10 despite x = y = 5 being evaluated first. Since y = 8, this tell us that x = 3 when y = x + y is being evaluated ? How is that possible if x = y is first evaluated, since it is evaluated left to right ?
I first debugged the code (which produced the same result), which I cannot understand. I also have tried looking at the python documentation, where it states "simultaneous overlaps within the collection of assigned-to variables occur left-to-right, sometimes resulting in confusion."
The example that it presents follows my logic:
x = [0, 1]
i = 0
i, x[i] = 1, 2
print(x)
It outputs 2.
(Evaluated left to right) Since i is updated to 1. Then, this updated i is used and hence, x[1] = 2 not x[0] = 2.
I really would appreciate some help.

I am not understanding why y = 8 instead of y = 10 despite x = y = 5 being evaluated first
The right side of an assignment is evaluated first.
In your assignment with x = 3 and y = 5
x, y = y, (x+y)
the right side is evaluated to a tuple (5, 8) first and then assigned to the values on the left side. Therefore y is 8.
You could also think of it as
x, y = 3, 5
temp = y, x + y
x, y = temp
To see what really happens internal, you can disassemble your code:
>>> import dis
>>> def f(x, y):
... x, y = y, x + y
...
>>> dis.dis(f)
Outputs
2 0 LOAD_FAST 1 (y)
2 LOAD_FAST 0 (x)
4 LOAD_FAST 1 (y)
6 BINARY_ADD
8 ROT_TWO
10 STORE_FAST 0 (x)
12 STORE_FAST 1 (y)
14 LOAD_CONST 0 (None)
16 RETURN_VALUE
As you can see, the addition is performed before the assignment.

Python goes right-to-left, left-to-right. You can imagine that python pushes its operations to a stack-like data structure.
Looking at the first assignment: x, y = 3, 5
python will first push the right-hand side value onto the stack as a tuple.
run an unpacking-sequence for n values from the stack, and puts the values back onto the stack right-to-left. "push 5 to the stack, then 3". Current stack = [3, 5]
Finished with the right-hand side, python will assign values to the left-hand side left-to-right, while removing top-of-stack. So it will first tak 3 and store it in variable x, then 5 and store it in variable y.
You can inspect the operations python does in byte code using the dis module.
The following assignments:
x, y = 3, 5
x, y = y, (x + y)
Produce the following operations:
You can inspect the bytecode operations here: http://pyspanishdoc.sourceforge.net/lib/bytecodes.html

Related

Python cvxpy - reuse some constraints

I'm currently using cvxpy to optimize a really big problem but now facing the current issue.
I run multiple iterations of the solver (every iteration reduces the flexibility of some variables).
Every run has 50 constraints in total, of which only 2 of them are different on every run. The remaining 48 constraints are identical.
During every iteration I rebuild from scratch those 2 constraints, the problem, and the obj function.
If I don't rebuild the remaining (same) 48 constraints, the final solution makes no sense.
I read this post CVXPY: how to efficiently solve a series of similar problems but here in my case, I don't need to change parameters and re-optimize.
I just managed to prepare an example that shows this issue:
x = cvx.Variable(3)
y = cvx.Variable(3)
tc = np.array([1.0, 1.0,1.0])
constraints2 = [x >= 2]
constraints3 = [x <= 4]
constraints4 = [y >= 0]
for i in range(2):
if i == 0:
constraints1 = [x - y >= 0]
else:
x = cvx.Variable(3)
y = cvx.Variable(3)
constraints1 = [x + y == 1,
x - y >= 1,
x - y >= 0,
x >= 0]
constraints = constraints1 + constraints2 + constraints3 + constraints4
# Form objective.
obj = cvx.Minimize( (tc.T # x ) - (tc.T # y ) )
# Form and solve problem.
prob = cvx.Problem(obj, constraints)
prob.solve()
solution_value = prob.value
solution = str(prob.status).lower()
print("\n\n** SOLUTION: {} Value: {} ".format(solution, solution_value))
print("* optimal (x + y == 1) dual variable", constraints[0].dual_value)
print("optimal (x - y >= 1) dual variable", constraints[1].dual_value)
print("x - y value:", (x - y).value)
print("x = {}".format(x.value))
print("y = {}".format(y.value))
As you can see, constraints2 requires all the values in the x vector to be greater than 2. constraints2 is added in both iterations to "constraints" that is used in the solver.
The second solution should give you values of vector x that are less than 2.
Why? How to avoid this issue?
Thank you
You need to use parameters as described in the linked post. Suppose you have the constraint rhs >= lhs which is sometimes used and other times not, where rhs and lhs have dimensions m x n. Write the following code:
param = cp.Parameter((m, n))
slack = cp.Variable((m, n))
param_constraint = [rhs >= lhs + cp.multiply(param, slack)]
Now to turn off the constraint, set param.values = np.ones((m, n)). To turn the constraint on, set param.values = np.zeros((m, n)). You can turn some entries of the constraint off/on by setting some entries of param to be 1 and others to be 0.

How are the values being determined in this basic Python class?

I am new to Python and to OOP concept. I was doing a EdX course and came across this code. I have modified it a little bit here. But I need to understand what exactly is happening here.
Question-1: Why does print(baba.x) give 7 but not 3?
Question-2: What does print(X) (capital X) do here? In getX and init I am using 'x' and not 'X'. So where does print(X) get its value from? It seems it is getting this value from the X=7 assignment. But isn't that assignment happening outside of the method getX and also outside of the class Weird. So why is getX able to access X=7 value?
I have searched on scope in Python, but was getting too complicated for me.
class Weird(object):
def __init__(lolo, x, y):
lolo.y = y
lolo.x = x
def getX(baba,x):
print (baba.x)
print (x)
print (X)
X = 7
Y = 8
w1 = Weird(X, Y)
print(w1.getX(3))
The output of the above code is:
7
3
7
None
Read What is the purpose of the word 'self', in Python?
class Weird(object):
def __init__(self, x, y):
self.y = y
self.x = x
def getX(self,x):
print (self.x) # this is the x value of this instance
print (x) # this is the x value you provide as parameter
print (X) # this might read the global X
X = 7
Y = 8
w1 = Weird(X, Y) # this sets w1.x to X (7) and w1.y to Y (8)
print(w1.getX(3)) # this provides 3 as local x param and does some printing

How to solve Equation without any Modules in Python?

I want to solve this equation without any Modules(NumPy, Sympy... etc.)
Px + Qy = W
(ex. 5x + 6y = 55)
Thanks.
It is a very crude way to do this, but you can use brute-force technique, as I said in comment under your question. It can probably be optimized a lot, gives only int outputs, but overall shows the method:
import numpy as np
# Provide the equation:
print("Provide a, b and c to evaluate in equation of form {ax + by - c = 0}")
a = float(input("a: "))
b = float(input("b: "))
c = float(input("c: "))
x_range = int(input("x-searching range (-a, a): "))
y_range = int(input("y-searching range (-b, b): "))
error = float(input("maximum accepted error from the exact solution: "))
x_range = np.arange(-x_range, x_range, 1)
y_range = np.arange(-y_range, y_range, 1)
for x in x_range:
for y in y_range:
if -error <= a * x + b * y - c <= error:
print("Got an absolute error of {} or less with numbers x = {} and y = {}.".format(error, x, y))
Example output for a = 1, b = 2, c = 3, x_range = 10, y_range = 10, error = 0.001:
Got an error of 0.001 or less with numbers x = -9 and y = 6.
Got an error of 0.001 or less with numbers x = -7 and y = 5.
Got an error of 0.001 or less with numbers x = -5 and y = 4.
Got an error of 0.001 or less with numbers x = -3 and y = 3.
Got an error of 0.001 or less with numbers x = -1 and y = 2.
Got an error of 0.001 or less with numbers x = 1 and y = 1.
Got an error of 0.001 or less with numbers x = 3 and y = 0.
Got an error of 0.001 or less with numbers x = 5 and y = -1.
Got an error of 0.001 or less with numbers x = 7 and y = -2.
Got an error of 0.001 or less with numbers x = 9 and y = -3.
I am using numpy, but not a built-in function to solve the equation itself, just to create an array. This can be done without it, of course.
There are thousands of ways to solve an equation with python.
One of those is:
def myfunc (x=None, y=None):
return ((55-6*y)/5.0) if y else ((55-5*x)/6.0)
print(myfunc(x=10)) # OUTPUT: 0.833333333333, y value for x == 10
print(myfunc(y=42)) # OUTPUT: -39.4, x value for y == 42
You simply define inside a function the steps required to solve the equation.
In our example, if we have y value we subtract 6*y to 55 then we divide by 5.0 (we add .0 to have a float as result), otherwise (means we have x) we subtract 5*x from 55 and then we divide by 6.0
with the same principle, you can generalize:
def myfunc (x=None, y=None, P=None, Q=None, W=None):
if not W:
return P*x + Q*y
elif not x:
return (W-Q*y)/float(P)
elif not y:
return (W-P*x)/float(Q)
elif not P:
return (W-Q*y)/float(x)
elif not Q:
return (W-P*x)/float(y)
print(myfunc(x=10, P=5, Q=6, W=55)) # OUTPUT: 0.833333333333, y value for x == 10
print(myfunc(y=42, P=5, Q=6, W=55)) # OUTPUT: -39.4, x value for y == 42
check this QA for some other interesting ways to approach this problem

how to define a certain value to equal to constant just for the first iteration?

I have a the following code (as an example):
answ = []
for i in range(1, 3):
x = y + 2
y = 3 + x
answ.append(y)
Where x and y are simultaneously determined. How can I determine them simultaneously? Or how can I assume that for the first loop y=0 (so x will equal to 2) and then starting from the second iteration 'y' = 3 + x.
Just set y to 0 before the for loop:
answ = []
y = 0
for i in range(1, 3):
x = y + 2
y = 3 + x
append.answ(y)
Like this:
x, y = y + 2, 3 + x
Right now, x and y are local variables, meaning they are deleted at the end of each iteration of the for loop. If you want them to carry over from the previous iteration, you need to define x and y outside of the for loop. This puts them above and the scope of the loop, so they don't get redefined.
Another thing, your for loop runs 2 times, because computers count from 0 and don't include the last number. Because i is not used in your loop at all, it would be better to do:
for i in range(2):
# code
But I am guessing that you want your loop to run three times, in which case you would write:
for i in range(3):
# code
I also noticed that you wrote append.answ(y) instead of answ.append(y). append is a member function of answ, so you would call it the second way.
Anyways, here is the final code for your program:
answ = []
x = 0
y = 0
for i in range(3):
x = y + 2
y = 3 + x
answ.append(y)

Accessing global variable in function in python

I have two pieces of code:
def g(y):
print(x)
x = 5
g(x)
and
def h(y):
x = x + 1
x = 5
h(x)
The first piece of code works perfectly fine printing '5' while the second piece returns:
UnboundLocalError: local variable 'x' referenced before assignment
What does this actually mean? Is it trying to say that it tried to evaluate the line x = x + 1 before it evaluates the line x=5? If that is so, why has the first piece of code not generated any error? It similarly had to evaluate the line print(x) before x was assigned a value.
I think I might have an misunderstanding how functions are called. But I do not know what it is that I got wrong.
# first block: read of global variable.
def g(y):
print(x)
x = 5
g(x)
# second block: create new variable `x` (not global) and trying to assign new value to it based on on this new var that is not yet initialized.
def h(y):
x = x + 1
x = 5
h(x)
If you want to use global you need to specify that explicitly with global keyword:
def h(y):
global x
x = x + 1
x = 5
h(x)
Just as Aiven said, or you can modify the code like this:
def h(y):
x = 9
x = x + 1
print(x) #local x
x = 5
h(x)
print(x) #global x

Resources