Copy a variable in python (jupyter) / Use different functions with same variables - python

I wrote a small Programm in python but it don't work like expected.
Here's the code:
puzzle = [8, 7, 5, 4, 1, 2, 3, 0, 6]
def count(p):
p[0] += 1
return p
def main(p):
print(p)
l = count(p)
print(l)
print(p)
b1 = main(puzzle)
I expect that print(p) will be different from print(l), but the result of both is the same, it's the result that print(l) should have. But p did change also, however I would need it to be unchanged… Is this a special python behavior? Is there something I missed?
I also tried to change the variable names in the functions, but that didn't help.
I restarted the Compiler, but that didn't help either.
Is there a solution to store a function output and than call the function again without let the function change the given parameters?
So that l will be the result after the calculation and p will stay the value before?
Kind Regards,
Joh.

You are passing a List parameter. Parameter passing is Call-by-Object. Since a List is a mutable object in this situation it is similar to pass by reference and changes to your List object will persist. If you were passing an immutable, such as an Integer or String, it would be akin to pass by copy/value, and changes would not persist. E.g.:
def s2asdf(s):
s = "asdf"
s = "hello world"
s2asdf(s)
print s
... results in:
$ python example.py
hello world

The reason for this is because Python passes function parameters by reference. When you call the count function it allows the function to modify the list inside the function and the changes will be applied to the original object.
If you want to have the function not modify the list but instead return a different list, you will have to make a copy of the list either by passing a copy to the function or make a copy inside the function itself. There are many ways to copy a list in Python, but I like to use the list() function to do it.
This should fix your problem:
puzzle = [8, 7, 5, 4, 1, 2, 3, 0, 6]
def count(p):
new_list = list(p) # copy values of p to new_list
new_list[0] += 1
return new_list
def main(p):
print(p)
l = count(p)
print(l) # l is the new_list returned from count
print(p) # p stays the original value
b1 = main(puzzle)

Related

When is it best to use a python map function with a user defined function with parentheses or without parentheses

Sorry if this sound like a dumb question, I really do not understand why am i getting values back and why the complier is not screaming error, first the below code the function add_to_five receive an (x) in the (parentheses) and return the value of x + 5; however when called in the map function i only pass in add_to_five without parentheses and provided a iterable sequence of l for the second arg and the new_value is [6, 7, 8, 9, 10]
how is x getting assigned, when called in the the map the add_to_five clearly does not get the parentheses explicitly assigned and the value of (x) is not provided to the function, however some how l is been replaced into the parentheses of add_to_five that why the result is [6, 7, 8, 9, 10].
when i take away (x +) in the return and just return only 5 though still left an (x) in the parentheses of add_to_five the new_value become [5,5,5,5,5] and i do not get an error when add_to_five referenced in the map function.
why does add_to_five work in the map function with out parentheses and also worked when i returned just (5) and still leave the (x) in the parentheses with out binding (x) to anything or value (5).
when is it best to use a function with parentheses as i know when invoked (type of add_to_five(5)) it return (int) as object type and when invoked (type of add_to_five) it returns function and random memory address.
I know lambda is a way to work around but not looking for quick solution thank you.
def add_to_five(x):
return x + 5
l = [1, 2, 3, 4, 5]
new_value = list(map(add_to_five, l))
print(new_value)
Think about functions in Python as simply objects. Objects can be passed to functions and also can be returned from functions. This is actually functional-style programming.
In your map function, you pass in a function and a list or any other object/collection that can be iterated.
Why you don't include the parantheses is because it is not a function call.
You'll always hear variables store data or references to data. But here the variable actually holds a reference to code.
When you create a function:
def func(arg1, arg2):
...
func is a function object. It is a variable that holds a reference to the code that is contained within the function.
If I do:
x = func
Here I have not used parantheses even though func is a function.
I can now do this:
x(1, 2)
It is because I assigned x as func. Calling x is equivalent to calling func.
This is a simplified form of how the map function works:
def map(function_to_call, iterable):
result = []
for element in iterable:
r = function_to_call(element)
result.append(r)
return result
Now I can go ahead and call map like this:
def square(x):
return x * x
map(square, [1, 2, 3, 4])
Map function does not return a list, it returns a map object that can be converted to a list. Here I have simplified it to prevent distraction.
So map takes in a function and a sequence, iterates over that sequence and calls the passed function on each and every element and creates a new sequence that contains the results. Map only takes a reference to the function so that it can call that function later during execution.
add_to_five similarly is a function object. It is passed to map so that map can call it later multiple times for each element.
This is advanced, so the confusion is common.
Hope this helps, let me know if something is not clear.
Maybe this helps explaining it:
Map is a function by it self, like any other function you provide the parameters for the function in (parentheses) and seperated by comma. Map works the same, only difference is that you do not insert an integer or string but a function, see here:
def add_to_five(x):
return x + 5
l = [1, 2, 3, 4, 5]
def map_function(a_function, lst):
for i, element in enumerate(lst):
lst[i] = a_function(element)
return lst
print(map_function(add_to_five, l))
#[6, 7, 8, 9, 10]

List is unchanged ever after element is changed

While trying to implement an algorithm, I couldn't get python lists to mutate via a function. After reading up on the issue I was suggested by this StackOverflow answer to use [:] in order to mutate the array passed in the function argumemt.
However, as seen in the following code snippet, the issue still persists when trying to mutate the list l. I am expecting the output to be Before: [1,2,3,4]
After: [69, 69, 69, 69], but instead I get back the original value of l as shown below.
def mutate_list(a, b):
c = [69] * 4
a[:] = c[:2] # changed the elements, but array's still unchanged outside function
b[:] = c[2:]
if __name__ == '__main__':
l = [1, 2, 3, 4]
print("Before: {}" .format(l))
mutate_list(l[:2], l[2:])
print("After: {}" .format(l))
Output:
Before: [1, 2, 3, 4]
After : [1, 2, 3, 4]
Any insights into why this is happening?
The error is that you not pass actually the l but two slices of it. You should change it, for example:
def mutate_list(a):
c = [69] * 4
a[:2] = c[:2]
a[2:] = c[2:]
if __name__ == '__main__':
l = [1, 2, 3, 4]
print("Before: {}" .format(l))
mutate_list(l)
print("After: {}" .format(l))
its all about the scope, mutable concept is applicable on list but not to reference variable.
The variables a,b are local variables, hence the scope of the variable will be always function scope.
The operations which you have performed :
a[:]=c[:2]
b[:]=c[2:]
Note: a and b both are list now so you will get following output in the function:
[69,69],[69,69]
but if you use + operator which is use for adding operations then the out out will be like:
[69,69,69,69]
Now whatever I told you that will be a local scope, if you want that the list should be mutable across the program then you have to specify the scope of the list as global inside function and on that variable you can do changes. in this case you also dont need to pass any arguments:
def mutate_list():
global l # telling python to use this global variable in a local function
c = [69] * 4
l=c # assigning new values to actual list i.e l
Now before output will be [1,2,3,4]
and after will be [69,69,69,69]
As pointed out by others, the issue arose from the fact that the function parameters were slices of the original array and as such, the parameters were being passed by value (instead of being passed by reference).
According to #Selcuk 's suggestion, the correct way of doing such an operation would be to pass the original array along with its indices to the function and then perform any slicing inside the function.
NOTE: This concept comes in handy for (recursive) divide-and-conquer algorithms where subarrays must be mutated and combined to form the solution.

Passing variable and list to function in Python

I don't understand this behaviour:
def getvariable(v):
v += 1
def getlist(l):
l.append(8)
myvariable = 1
mylist = [5, 6, 7]
print myvariable, mylist
getvariable(myvariable)
getlist(mylist)
print myvariable, mylist
Output:
1 [5, 6, 7]
1 [5, 6, 7, 8]
Why list changed, but variable doesn't?
How can I change variable in function?
Many people say about passing by value, by reference, by object reference, so I am a bit confused and don't know how it is really.
In python integers are immutable. v += 1 only binds a new integer value to the name v, which is local in your function. It does not modify the integer in place.
Lists in python are mutable. You pass a list (by reference, as always in python), and the function changes it in place. That's why the change is "seen" externally to the function.
There is no such thing as "passing by value" in python.
What you probably want to do is return v+1 from your function, not to modify the value bound to the name v.
Because, lists are mutable but integers are immutable.
Read more about it here: http://docs.python.org/2/reference/datamodel.html#objects-values-and-types

Temporary created during python list iteration?

I want to understand why the following is happening. My guess is that a temporary is being created during list iteration, but want some experts to confirm this:
def test():
a=[set([1,2,3]),set([3,4,5])]
x=set([1,4])
for i in a:
# doesn't actually modify list contents, making a copy of list elements in i?
i=i.difference(x)
print a
for idx,i in enumerate(a):
i=i.difference(x)
print id(i),id(a[idx])
# obviously this modifies the contents
a[idx]=i
print a
Output:
[set([1, 2, 3]), set([3, 4, 5])]
59672976 59672616
59672616 59672736
[set([2, 3]), set([3, 5])]
Also, I want to understand why the "id" of i in the second iteration is the same as the "id" for a[0].
It helps to look at this graphically, because it's basically a pointer problem.
for i in a iteratively assigns i to each element in a.
i = i.difference(x) creates and assigns i to it.
Let's take this one step at a time:
i.difference(x) doesn't modify i or x. Rather, it returns a new set.
i = i.difference(x) rebinds the variable i to point to the new set. It does not affect the contents of the list in any way.
a[idx] = i does modify the list by setting its idx-th element to the new set.
A cleaner implementation might use a different variable instead of re-purposing i:
def test():
a=[set([1,2,3]),set([3,4,5])]
x=set([1,4])
for i in a:
diff=i.difference(x)
# a[idx]=diff
print a
Yes, when you execute i=i.difference(x) it creates a new i. Just modify your code like this to understand what is happening -
def test():
a=[set([1,2,3]),set([3,4,5])]
x=set([1,4])
for i in a:
# doesn't actually modify list contents, making a copy of list elements in i?
print 'old i - ', id(i)
i=i.difference(x)
print 'new i - ', id(i)
print a
test()
Output -
old i - 4467059736
new i - 4467179216
old i - 4467177360
new i - 4467179216
[set([1, 2, 3]), set([3, 4, 5])]
Your use of set.difference() suggests that you don't know the operator -= for sets:
def test():
a=[set([1,2,3]),set([3,4,5])]
x=set([1,4])
for i in a:
i -= x
print a
This shows that i is just another pointer to the set you want to modify. Just don't overwrite your pointer!

python passing argument to a function

folks, i got a question about passing mutable object to a function
with the following code, I was expecting the output to be [0,0,0], while the output is [0,1,2,3]
does it mean the argument is actually copied and then send to the inside of the function?
def lala(a):
n = [0, 0 , 0]
a = n
a = [0,1,2,3]
lala(a)
print a
if i want to fulfill the above task inside the function, how shall i write it elegantly?
thanks very much!
Python makes more sense if you think of attaching name tags to objects, rather than stuffing objects into named boxes.
def lala(a):
n = [0, 0 , 0]
a = n
Here's what's happening.
You're receiving a parameter (a list in this case) and giving it the name a.
You're creating a new list and giving it the name n.
You are giving the list you named n the additional name a.
Both names, a and n, are local to the lala function, so they "expire" when the function ends.
The list you created in the function now has no names, and Python discards it.
In other words, a is not a box into which you can put a new list. It is a name you gave a list you received. Later, you reassign that name to the list you have also named n.
Others have suggested a slice assignment, a[:] = n, which uses a reference to the items in the list rather than the list itself. When you do this, the name a still points to the same list; its contents have just been replaced. Since it is the same list that was passed into the function, any names by which it is known outside the function will "see" the new contents.
kindall provided a great explanation in my opinion, but my preferred method for doing something like this is to have the function return the change instead of messing with references.
def lala():
n = [0, 0, 0]
return n
a = [0, 1, 2, 3]
a = lala()
print a # prints [0, 0, 0]
you can use a[:] = n inside the function. this is called a slice assignment
python does not have a call-by-reference feature. There's no general way to do this.
If you know your argument is going to be a list, and you want it to take a different value, you can write it like so:
def lala(a):
a[:] = [0,0,0]
That's because a function makes new label "a" for its scope. Then this "a" overshadows the "a" you defined outside the function. So the new label a is assigned to new object [0,0,0,0]
If you would write:
def lala(a):
a.pop()
a = [0,1,2,3,4]
lala(a)
print(a)
You would see that a = [0,1,2,3] because pop() actually change the object which label 'a' points to. (while assignment just change to what object given label points to)
Note the difference between your function, and this one:
def lala(a):
a[0] = 7
a = [0,1,2,3]
lala(a)
print a # prints [7, 1, 2, 3]

Categories

Resources