Details about how a=b=c works - python

From this answer: How do chained assignments work?, I understand that chained assignement in Python :
x = y = z # (1)
is equivalent to:
temp = z
x = temp
y = temp
But is (1) also equivalent to:
x = z
y = x
?
Or is there a slight difference (for example when z = some_function())? If so, which difference?

In the very example you give, yes, the effects of the two approaches are practically identical because both involve simply assigning the same reference to a number of names.
Be aware, however, that if the expressions in the assignment targets involve more complex evaluations, the two approaches could be different.
For example, consider the following chain expression, where x is initialized as a dict and expensive_func is a time-consuming function that returns a key:
x[expensive_func()] = y = some_function()
While it would be indeed equivalent to the following:
temp = some_function()
x[expensive_func()] = temp
y = temp
it would not be be equivalent to the second approach:
x[expensive_func()] = some_function()
y = x[expensive_func()]
since expensive_func would then have to be called twice, doubling the time taken, and triggering the side effect of the function twice, if it has any.
Also, consider the following code:
obj = []
x = []
x[:] = y = obj
print(id(obj), id(x), id(y))
where the output would show that y gets assigned the same reference as obj, while x is different.
That code is then indeed equivalent to:
obj = []
x = []
temp = obj
x[:] = temp
y = temp
print(id(obj), id(x), id(y))
But not equivalent to:
obj = []
x = []
x[:] = obj
y = x[:]
print(id(obj), id(x), id(y))
The latter of which would show y getting a different reference from both obj and x.

I always find using examples to be the best way to understand things (in general).
Let's say we have a func:
def function_sample ():
print(20)
If you print it:
print(function_sample)
<function function_sample at 0x7f8f840a01f0>
returns the function object.
When assigning to a variable a function without parentheses (without calling/running it).
x = function_sample
print(x)
you will get the same message: <function function_sample at 0x7f8f840a01f0>
However, if you run it (with parentheses).
print(x())
You will see :
20
None
Why None? It's because Python functions have a default return value, which is None if no return expression is given, or return is given on its own.
Another sample:
def another_sample(some):
print(some)
y = another_sample
print(y)
As you probably have guessed it : <function another_sample at 0x7f8f7e747700>
If you try to print y() you will get an error because the some argument is missing.
But if we add one:
print(y(5))
5
None
One last example:
def third_sample ():
return 20
aa = third_sample # without running the func
bb = third_sample() # calling/running the func
print(aa) # function object
print(bb) # 20

The 2 approaches you have shown are both functional and legit in terms of going about chaining and using previous variables. No difference at all
When assigning variables to the same number of variables, instead of doing the typical:
x = 0
y = 0
OR using tuple unpacking approach:
(x,y) = 0,0
You could just do like what you have (chained assignment):
x = y = 0
This could be used with any object (being called on) for the RHS, and that:
x = y = some_object()
is the same as:
tmp = some_object()
x = tmp
y = tmp
and when you del tmp, the xand y become useless or nothing.

Related

The solution always returns x=0

On using this code I get the value returned 0 always
def fi(arr,mini):
print(arr)
if(len(arr)<3):
x = mini
return
for j in range(1,(math.ceil(len(arr)/2) )):
l1 = 2*j+1
if(med(arr[0:l1])<mini):
mini= med(arr[0:l1])
print("hello", mini)
fi(arr[1:],mini)
return x
You define x only if len(arr) < 3. In other cases it is unassigned. You should add a default value before the if block, or within an else block depending on what you are trying to do.
You haven't declared x before assigning it to mini. What should your function return by default?
you define local variable 'x' whose scope is limited to if block and you are trying to return this variable from the function, so it's getting undefined. Better define local variable x in the function and give it some default value which should be return by the function.
def fi(arr,mini):
x = some_default_value
print(arr)
if(len(arr)<3):
x = mini
return
for j in range(1,(math.ceil(len(arr)/2) )):
l1 = 2*j+1
if(med(arr[0:l1])<mini):
mini= med(arr[0:l1])
print("hello", mini)
fi(arr[1:],mini)
return x

python - Why does emptying a list and appending to it in a function gives empty lists?

This piece of code gives empty lists in the print statement:
X = []
Y = []
Z = []
def DoStuff(a,b,c):
X = []
Y = []
Z = []
X.append(a)
Y.append(b)
Z.append(c)
DoStuff(1,2,3)
print('X:{0}\nY:{1}\nZ:{2}'.format(X,Y,Z))
I know I can 'fix' by adding a return-statement:
X = []
Y = []
Z = []
def DoStuff(a,b,c):
X = []
Y = []
Z = []
X.append(a)
Y.append(b)
Z.append(c)
return X, Y, Z
X, Y, Z = DoStuff(1,2,3)
print('X:{0}\nY:{1}\nZ:{2}'.format(X,Y,Z))
But why does the first code gives empty lists?
Because you are defining the list at the start of the code. Also, only the second code reassign values to list
In your first example, the scope of the X, Y, Z variables that you are appending is restricted to the DoStuff function.
Basically, you have two types of variables here: Inside the function and Outside the function. In your second example you are returning the values of InsideX, InsideY, InsideZ and then overwriting OutsideX, OutsideY, and OutsideZ with this line:
X, Y, Z = DoStuff(1,2,3)
It's because they are local variables. Meaning that their lifespan resides between the beginning and the end of the function block. Even though they have the same name with the global variables, they "hide" the global ones when they are within the block.
So actually you're not "emptying" the lists. If you want to modify a global variable in a function block, you can declare them as global foo inside the block. However, this practice is heavily discouraged in the community.

Python pathos mutiprocessing, one list and one object as arguments

I want to use multiprocessing to accelerate multiple calls to a function, the function takes as argument two values, a variable that changes for every calculation and a constant variable.
Here is a code that emulates my problem:
import pathos.pools as pp
p = pp.ProcessPool(4)
def add(x,y):
return x+y
x = [0,1,2,3]
y = 5
result = p.map(add, x, y)
As y is not a list I get the following error:
TypeError: izip argument #2 must support iteration
In this simple case the straightforward solution would be to make y a list of the constant values:
y = [5 for value in x]
But I would like to avoid this solution as in my case y is a complex object that takes up quite a big chunk of memory.
Thanks for any suggestions
you can just use local variables for the function you declare. I often make a wrapper to pass non-iterables, e.g.
def add(x,y):
return x+y
def add_wrapper(x):
y = 5
return add(x,y)
x = [0,1,2,3]
result = p.map(add_wrapper, x)
or
def add(x,y):
return x+y
def add_wrapper(x):
return add(x,y)
y = 5
x = [0,1,2,3]
result = p.map(add_wrapper, x)

How exactly does the caller see a change in the object?

From Chapter "Classes" of the official Python tutorial:
[...] if a function modifies an object passed as an argument, the caller will see the change — this eliminates the need for two different argument passing mechanisms as in Pascal.
What would be an example of how exactly the caller will see a change? Or how could it be (not in Python but in general) that the caller doesn't see the change?
It basically means that if a mutable object is changed, it will change everywhere.
For an example of passing by reference (which is what Python does):
x = []
def foo_adder(y):
y.append('foo')
foo_addr(x)
print(x) # ['foo']
vs something like Pascal, where you can pass copies of an object as a parameter, instead of the object itself:
# Pretend this is Pascal code.
x = []
def foo_adder(y):
y.append('foo')
foo_adder(x)
print(x) # []
You can get the behavior of the second example in Python if you pass a copy of the object. For lists, you use [:].
# Pretend this is Pascal code.
x = []
def foo_adder(y):
y.append('foo')
foo_adder(x[:])
print(x) # []
For your second question about how the caller might not see the change, let's take that same foo_adder function and change it a little so that it doesn't modify the object, but instead replaces it.
x = []
def foo_adder(y):
y = y + ['foo']
foo_adder(x)
print(x) # []
What would be an example of how exactly the caller will see a change?
>>> def modify(x):
... x.append(1)
...
>>> seq = []
>>> print(seq)
[]
>>> modify(seq)
>>> print(seq)
[1]
Or how could it be (not in Python but in general) that the caller doesn't see the change?
Hypothetically, a language could exist where a deep copy of seq is created and assigned to x, and any change made to x has no effect on seq, in which case print(seq) would display [] both times. But this isn't what happens in Python.
Edit: note that assigning a new value to an old variable name typically doesn't count as "modification".
>>> def f(x):
... x = x + 1
...
>>> y = 23
>>> f(y)
>>> print(y)
23

Looping through a function in python but redefining a variable when a function from an array of functions gets called

Say I have the following example, in python:
import numpy as np, PROGRAMS as prg
testlist = []
x = 0
n=0
y=[1,2,3,4,5]
x_fn = np.array=([prg.test1(x),prg.test2(x),prg.test3(x)])
for i in range(0,len(x_fn)):
for j in range(0, len(y)):
x = y[j]*2
z=x_fn[i]
testlist.append(z)
j = j+1
i = i+1
print testlist
#####PROGRAMS
def test1(x):
x=x**2
return x
def test2(x):
x=x**3
return x
def test3(x):
x=x+10
return x
If x isn't defined before x_fn then an error occurs but if I define it as zero then that is what is used in the calculations. I basically want this code to produce a list with the the defined value of x in the 2nd loop :
x = y[j]*2
for all values of y. I know there would be a way around this mathematically - but I would like to solve it by running the same function and not changing any of the values of y or any of the functions in PROGRAMS.
Basically, is it a good idea to put these functions in a array and run through it element by element or is there a better way to do it?
Thanks in advance for your replies,
Sven D.
Could this be what you want ?
def test1(x):
x=x**2
return x
def test2(x):
x=x**3
return x
def test3(x):
x=x+10
return x
testlist = []
n=0
y_vals=[1,2,3,4,5]
x_fn = [test1, test2, test3]
for fun in x_fn:
for y in y_vals:
x = y*2
z=fun(x)
testlist.append(z)
print testlist
Functions are objects that can be stored in containers and recalled for use later just like any other object in Python.
You don't even need to use numpy arrays. Just use a list (functions) and put the test functions in it. Note, that I have removed the argument. The elements of the functions array are references to the functions, so you can use them in your loop.
import PROGRAMS as prg
testlist = []
y=[1,2,3,4,5]
functions = [prg.test1, prg.test2, prg.test3]
for func in functions:
for j in y:
x = j*2
z = func(x)
testlist.append(z)
print testlist
#####PROGRAMS
def test1(x):
x=x**2
return x
def test2(x):
x=x**3
return x
def test3(x):
x=x+10
return x

Categories