This question already has answers here:
What are the differences between swap in C++ and Python?
(4 answers)
Closed 7 years ago.
I think the output should be x = 5, y = 3. But, when I tried executing it in jes it shows that x=3 and y=5.
My swap function is as follows:
def swap (x,y):
temp=x
x=y
y=temp
And from my driver function I call swap():
def driver():
x=3
y=5
swap(x,y)
print x
print y
I want to know why isn't the output as expected?
Well this is not a big issue in python you can return multiple values like try this snippet it might help you.
def swap(a,b):
return (b,a)
def driver(x,y):
print "Previous x=",x,"y=",y
x,y = swap(x,y)
print "Now x=", x, "y=",y
driver(3,5)
As other answers have suggested, this really doesn't require functions. Since you have decided to use them though, you might as well try and understand a bit more about scopes.
In order to retain the swapped values you need to return them or else they get lost after the execution of swap():
def swap (x,y):
temp=x
x=y
y=temp
return x, y # must return the swapped values.
Then, in the function where you call swap() you assign the returned values to the variables that you swapped:
def driver():
x=3
y=5
x, y = swap(x,y) # re-assign values
print x
print y
Running driver() now will give you the swapped value:
5
3
This happens because in the function swap() the variables x and y you pass as arguments are treated as local to that function, only swap can see their value. If you don't return this value back, it is lost and forgotten.
Integers are immutable in python. You are setting y to x and x to y in the local scope, but are not modifying the reference to the initial integers passed in. In python, the best you can do if you want to encapsulate a swap function that modifies in-place instead of by return is pass some kind of container object that is mutable and contain references to the thing you want to swap:
def swap(container):
container[0], container[1] = container[1], container[0]
And then call it like so:
x = 3
y = 5
container = [x,y]
swap(container)
FWIW, swap in python can be implemented in one line as simply as:
x, y = y, x
Which is probably syntactically clearer in most cases anyway.
See also Python passing an integer by reference
In python assignment changes the identity of an object rather than its value (unless you are mutating the content). This is worth noting that, as per Python Data Model
Every object has an identity, a type and a value.
So interchanging the identities inside swap would not change the identity inside the driver. Moreover, python does not allow you to change the value of an immutable types so, there is no other possible ways to swap the values inside the swap method.
Related
This question already has answers here:
Why can a function modify some arguments as perceived by the caller, but not others?
(13 answers)
Closed 7 months ago.
Once I define a list in main() and passed it as a function parameter, I expected that its content will remain the same once we exit the function. I have the following code snippet:
def test(a):
a.append(1000)
return a
def main():
a = [1,2,3]
print(a, test(a))
main()
Output is clear.
# Output: [1,2,3,1000] [1,2,3,1000]
Even though the initial list contains 3 elements, function test() seems to modify its content. This thing does not happen to variables:
def test(a):
a = a + 10
return a
def main():
a = 5
print(a, test(a))
main()
# Output: 5 15
Why is that? Why does Python modify the initial lists and not variables?
a.append()
mutates the a which was passed by reference
a = a + 10
assigns a value to a new local variable in the function called a
Integers are immutable, but if there were some method that could be called on that a (on the right hand side) to mutate it, it would also be reflected in the caller.
Some objects in python (like lists, dicts and sets) are mutable, whereas others (like tuples, frozensets, strings and numbers) are immutable.
Operations on mutable objects modify the object themselves. Many immutable objects also allow operations, which in this case return a new object. (Internally this is implemented with the dunder "magic methods", which in this case just return a new object. x OPERATOR y actually calls a method on x(and/or y).)
Since in python x = y binds the name x to point to y, if y is mutable and you modify it, x will point to the modified y. But if y is immutable (but allows operations), operations on y will create a new y, to which x no longer points:
x = [] # mutable
y = x # y and x both point to a particular '[]'
x += ["hi"]
y == ["hi"] # True
x = 0
y = x # y and x both point to 0
x += 7 # x now points to 7
y == 7 # False
Exactly the same thing goes on when you parse an argument to a function---you bind a name in the function's scope pointing to that object. What then happens to the object pointed to by the name depends upon the type of object and what you do to it. If it's mutable and you mutate the object pointed to by the name in the function, you will mutate the object itself, and any other names bound to that object ouside the function will see the changed object.
This is the reason that we don't generally do this:
def f(x=[]):
...
Since f is evaluated once, when the module is first loaded, x will point to the same list for the duration of the function. Thus if the function does anything to x, x will be in that state next time it's called (which is rarely what you want).
This question already has answers here:
"Least Astonishment" and the Mutable Default Argument
(33 answers)
Closed 3 years ago.
As a C++ programmer I got unexpected behaviour in Python. In the example below, the output is:
y:A1
A1
B1
I however would have expected this output:
B1
I used python 2.7. For me it is surprising that in the second call of the function the default parameter has already the value from the result of the previous call. Should it not be an empty list?
Here is the python code:
def f( x, y=[]):
for z in y:
print "y:" + str(z)
result = y
result.append(x+'1')
return result
l = f('A')
l = f('B')
for x in l:
print x
Edit:
As indicated by others, this question is a duplicate. The the short answer is that python evaluates default parameters only once at program start and stores the result statically in the function. From C++ I would have expected that it is evaluated every time the function is called and stored only locally and not static.
In my code I see two dangerous situations with this behaviour:
A) the function should modify a list but it should start with an empty list if the parameter is not passed at function call. Now I had the problem that the list grew more and more.
The solution would be
a) remove the default value of the parameter in order I am forced to provide an empty list at least:
def f( x, y):
result = y
result.append(x+'1')
return result
l = f('A',[])
l = f('B',[])
b) Use None as default parameter:
def f( x, y=None):
result = y or []
result.append(x+'1')
return result
B) The other problem is that the default parameter is calculated at program start and I used a timestamp of now as default parameter...
result = y makes the names result and y point to the same object in memory, so the list y in the second call will not be empty (because now any modification to result will also appear in y (in your case you're appending to it)), try this (list slicing) and it will give you your desired output:
result = y[:] # elements of y, from the first to the last
This slicing is equivalent to result = y in the values, but result and y will point to two different objects in memory, because slicing creates a new list.
This question already has answers here:
Why can a function modify some arguments as perceived by the caller, but not others?
(13 answers)
Closed 3 years ago.
Let's take a simple code:
y = [1,2,3]
def plusOne(y):
for x in range(len(y)):
y[x] += 1
return y
print plusOne(y), y
a = 2
def plusOne2(a):
a += 1
return a
print plusOne2(a), a
Values of 'y' change but value 'a' stays the same. I have already learned that it's because one is mutable and the other is not. But how to change the code so that the function doesn't change the list?
For example to do something like that (in pseudocode for simplicity):
a = [1,2,3,...,n]
function doSomething(x):
do stuff with x
return x
b = doSomething(a)
if someOperation(a) > someOperation(b):
do stuff
EDIT: Sorry, but I have another question on nested lists. See this code:
def change(y):
yN = y[:]
for i in range(len(yN)):
if yN[i][0] == 1:
yN[i][0] = 0
else:
yN[i][0] = 1
return yN
data1 = [[1],[1],[0],[0]]
data2 = change(data1)
Here it doesn't work. Why? Again: how to avoid this problem? I understand why it is not working: yN = y[:] copies values of y to yN, but the values are also lists, so the operation would have to be doubled for every list in list. How to do this operation with nested lists?
Python variables contain pointers, or references, to objects. All values (even integers) are objects, and assignment changes the variable to point to a different object. It does not store a new value in the variable, it changes the variable to refer or point to a different object. For this reason many people say that Python doesn't have "variables," it has "names," and the = operation doesn't "assign a value to a variable," but rather "binds a name to an object."
In plusOne you are modifying (or "mutating") the contents of y but never change what y itself refers to. It stays pointing to the same list, the one you passed in to the function. The global variable y and the local variable y refer to the same list, so the changes are visible using either variable. Since you changed the contents of the object that was passed in, there is actually no reason to return y (in fact, returning None is what Python itself does for operations like this that modify a list "in place" -- values are returned by operations that create new objects rather than mutating existing ones).
In plusOne2 you are changing the local variable a to refer to a different integer object, 3. ("Binding the name a to the object 3.") The global variable a is not changed by this and continues to point to 2.
If you don't want to change a list passed in, make a copy of it and change that. Then your function should return the new list since it's one of those operations that creates a new object, and the new object will be lost if you don't return it. You can do this as the first line of the function: x = x[:] for example (as others have pointed out). Or, if it might be useful to have the function called either way, you can have the caller pass in x[:] if he wants a copy made.
Create a copy of the list. Using testList = inputList[:]. See the code
>>> def plusOne(y):
newY = y[:]
for x in range(len(newY)):
newY[x] += 1
return newY
>>> y = [1, 2, 3]
>>> print plusOne(y), y
[2, 3, 4] [1, 2, 3]
Or, you can create a new list in the function
>>> def plusOne(y):
newList = []
for elem in y:
newList.append(elem+1)
return newList
You can also use a comprehension as others have pointed out.
>>> def plusOne(y):
return [elem+1 for elem in y]
You can pass a copy of your list, using slice notation:
print plusOne(y[:]), y
Or the better way would be to create the copy of list in the function itself, so that the caller don't have to worry about the possible modification:
def plusOne(y):
y_copy = y[:]
and work on y_copy instead.
Or as pointed out by #abarnet in comments, you can modify the function to use list comprehension, which will create a new list altogether:
return [x + 1 for x in y]
Just create a new list with the values you want in it and return that instead.
def plus_one(sequence):
return [el + 1 for el in sequence]
As others have pointed out, you should use newlist = original[:] or newlist = list(original) to copy the list if you do not want to modify the original.
def plusOne(y):
y2 = list(y) # copy the list over, y2 = y[:] also works
for i, _ in enumerate(y2):
y2[i] += 1
return y2
However, you can acheive your desired output with a list comprehension
def plusOne(y):
return [i+1 for i in y]
This will iterate over the values in y and create a new list by adding one to each of them
To answer your edited question:
Copying nested data structures is called deep copying. To do this in Python, use deepcopy() within the copy module.
You can do that by make a function and call this function by map function ,
map function will call the add function and give it the value after that it will print the new value like that:
def add(x):
return x+x
print(list(map(add,[1,2,3])))
Or you can use (*range) function it is very easy to do that like that example :
print ([i+i for i in [*range (1,10)]])
This question already has answers here:
Why can a function modify some arguments as perceived by the caller, but not others?
(13 answers)
Closed 3 years ago.
Let's take a simple code:
y = [1,2,3]
def plusOne(y):
for x in range(len(y)):
y[x] += 1
return y
print plusOne(y), y
a = 2
def plusOne2(a):
a += 1
return a
print plusOne2(a), a
Values of 'y' change but value 'a' stays the same. I have already learned that it's because one is mutable and the other is not. But how to change the code so that the function doesn't change the list?
For example to do something like that (in pseudocode for simplicity):
a = [1,2,3,...,n]
function doSomething(x):
do stuff with x
return x
b = doSomething(a)
if someOperation(a) > someOperation(b):
do stuff
EDIT: Sorry, but I have another question on nested lists. See this code:
def change(y):
yN = y[:]
for i in range(len(yN)):
if yN[i][0] == 1:
yN[i][0] = 0
else:
yN[i][0] = 1
return yN
data1 = [[1],[1],[0],[0]]
data2 = change(data1)
Here it doesn't work. Why? Again: how to avoid this problem? I understand why it is not working: yN = y[:] copies values of y to yN, but the values are also lists, so the operation would have to be doubled for every list in list. How to do this operation with nested lists?
Python variables contain pointers, or references, to objects. All values (even integers) are objects, and assignment changes the variable to point to a different object. It does not store a new value in the variable, it changes the variable to refer or point to a different object. For this reason many people say that Python doesn't have "variables," it has "names," and the = operation doesn't "assign a value to a variable," but rather "binds a name to an object."
In plusOne you are modifying (or "mutating") the contents of y but never change what y itself refers to. It stays pointing to the same list, the one you passed in to the function. The global variable y and the local variable y refer to the same list, so the changes are visible using either variable. Since you changed the contents of the object that was passed in, there is actually no reason to return y (in fact, returning None is what Python itself does for operations like this that modify a list "in place" -- values are returned by operations that create new objects rather than mutating existing ones).
In plusOne2 you are changing the local variable a to refer to a different integer object, 3. ("Binding the name a to the object 3.") The global variable a is not changed by this and continues to point to 2.
If you don't want to change a list passed in, make a copy of it and change that. Then your function should return the new list since it's one of those operations that creates a new object, and the new object will be lost if you don't return it. You can do this as the first line of the function: x = x[:] for example (as others have pointed out). Or, if it might be useful to have the function called either way, you can have the caller pass in x[:] if he wants a copy made.
Create a copy of the list. Using testList = inputList[:]. See the code
>>> def plusOne(y):
newY = y[:]
for x in range(len(newY)):
newY[x] += 1
return newY
>>> y = [1, 2, 3]
>>> print plusOne(y), y
[2, 3, 4] [1, 2, 3]
Or, you can create a new list in the function
>>> def plusOne(y):
newList = []
for elem in y:
newList.append(elem+1)
return newList
You can also use a comprehension as others have pointed out.
>>> def plusOne(y):
return [elem+1 for elem in y]
You can pass a copy of your list, using slice notation:
print plusOne(y[:]), y
Or the better way would be to create the copy of list in the function itself, so that the caller don't have to worry about the possible modification:
def plusOne(y):
y_copy = y[:]
and work on y_copy instead.
Or as pointed out by #abarnet in comments, you can modify the function to use list comprehension, which will create a new list altogether:
return [x + 1 for x in y]
Just create a new list with the values you want in it and return that instead.
def plus_one(sequence):
return [el + 1 for el in sequence]
As others have pointed out, you should use newlist = original[:] or newlist = list(original) to copy the list if you do not want to modify the original.
def plusOne(y):
y2 = list(y) # copy the list over, y2 = y[:] also works
for i, _ in enumerate(y2):
y2[i] += 1
return y2
However, you can acheive your desired output with a list comprehension
def plusOne(y):
return [i+1 for i in y]
This will iterate over the values in y and create a new list by adding one to each of them
To answer your edited question:
Copying nested data structures is called deep copying. To do this in Python, use deepcopy() within the copy module.
You can do that by make a function and call this function by map function ,
map function will call the add function and give it the value after that it will print the new value like that:
def add(x):
return x+x
print(list(map(add,[1,2,3])))
Or you can use (*range) function it is very easy to do that like that example :
print ([i+i for i in [*range (1,10)]])
This question already has answers here:
Does Python make a copy of objects on assignment?
(5 answers)
How do I pass a variable by reference?
(39 answers)
Why can a function modify some arguments as perceived by the caller, but not others?
(13 answers)
Closed last month.
For a project I'm working on, I'm implementing a linked-list data-structure, which is based on the idea of a pair, which I define as:
class Pair:
def __init__(self, name, prefs, score):
self.name = name
self.score = score
self.preferences = prefs
self.next_pair = 0
self.prev_pair = 0
where self.next_pair and self.prev_pair are pointers to the previous and next links, respectively.
To set up the linked-list, I have an install function that looks like this.
def install(i, pair):
flag = 0
try:
old_pair = pair_array[i]
while old_pair.next_pair != 0:
if old_pair == pair:
#if pair in remainders: remainders.remove(pair)
return 0
if old_pair.score < pair.score:
flag = 1
if old_pair.prev_pair == 0: # we are at the beginning
old_pair.prev_pair = pair
pair.next_pair = old_pair
pair_array[i] = pair
break
else: # we are not at the beginning
pair.prev_pair = old_pair.prev_pair
pair.next_pair = old_pair
old_pair.prev_pair = pair
pair.prev_pair.next_pair = pair
break
else:
old_pair = old_pair.next_pair
if flag==0:
if old_pair == pair:
#if pair in remainders: remainders.remove(pair)
return 0
if old_pair.score < pair.score:
if old_pair.prev_pair==0:
old_pair.prev_pair = pair
pair.next_pair = old_pair
pair_array[i] = pair
else:
pair.prev_pair = old_pair.prev_pair
pair.next_pair = old_pair
old_pair.prev_pair = pair
pair.prev_pair.next_pair = pair
else:
old_pair.next_pair = pair
pair.prev_pair = old_pair
except KeyError:
pair_array[i] = pair
pair.prev_pair = 0
pair.next_pair = 0
Over the course of the program, I am building up a dictionary of these linked-lists, and taking links off of some and adding them in others. Between being pruned and re-installed, the links are stored in an intermediate array.
Over the course of debugging this program, I have come to realize that my understanding of the way Python passes arguments to functions is flawed. Consider this test case I wrote:
def test_install():
p = Pair(20000, [3, 1, 2, 50], 45)
print p.next_pair
print p.prev_pair
parse_and_get(g)
first_run()
rat = len(juggler_array)/len(circuit_array)
pref_size = get_pref_size()
print pref_size
print install(3, p)
print p.next_pair.name
print p.prev_pair
When I run this test, I get the following result.
0
0
10
None
10108
0
What I don't understand is why the second call to p.next_pair produces a different result (10108) than the first call (0). install does not return a Pair object that can overwrite the one passed in (it returns None), and it's not as though I'm passing install a pointer.
My understanding of call-by-value is that the interpreter copies the values passed into a function, leaving the caller's variables unchanged. For example, if I say
def foo(x):
x = x+1
return x
baz = 2
y = foo(baz)
print y
print baz
Then 3 and 2 should be printed, respectively. And indeed, when I test that out in the Python interpreter, that's what happens.
I'd really appreciate it if anyone can point me in the right direction here.
In Python, everything is an object. Simple assignment stores a reference to the assigned object in the assigned-to name. As a result, it is more straightforward to think of Python variables as names that are assigned to objects, rather than objects that are stored in named locations.
For example:
baz = 2
... stores in baz a pointer, or reference, to the integer object 2 which is stored elsewhere. (Since the type int is immutable, Python actually has a pool of small integers and reuses the same 2 object everywhere, but this is an implementation detail that need not concern us much.)
When you call foo(baz), foo()'s local variable x also points to the integer object 2 at first. That is, the foo()-local name x and the global name baz are names for the same object, 2. Then x = x + 1 is executed. This changes x to point to a different object: 3.
It is important to understand: x is not a box that holds 2, and 2 is then incremented to 3. No, x initially points to 2 and that pointer is then changed to point to 3. Naturally, since we did not change what object baz points to, it still points to 2.
Another way to explain it is that in Python, all argument passing is by value, but all values are references to objects.
A counter-intuitive result of this is that if an object is mutable, it can be modified through any reference and all references will "see" the change. For example, consider this:
baz = [1, 2, 3]
def foo(x):
x[0] = x[0] + 1
foo(baz)
print baz
>>> [2, 2, 3]
This seems very different from our first example. But in reality, the argument is passed the same way. foo() receives a pointer to baz under the name x and then performs an operation on it that changes it (in this case, the first element of the list is pointed to a different int object). The difference is that the name x is never pointed to a new object; it is x[0] that is modified to point to a different object. x itself still points to the same object as baz. (In fact, under the hood the assignment to x[0] becomes a method call: x.__setitem__().) Therefore baz "sees" the modification to the list. How could it not?
You don't see this behavior with integers and strings because you can't change integers or strings; they are immutable types, and when you modify them (e.g. x = x + 1) you are not actually modifying them but binding your variable name to a completely different object. If you change baz to a tuple, e.g. baz = (1, 2, 3), you will find that foo() gives you an error because you can`t assign to elements of a tuple; tuples are another immutable type. "Changing" a tuple requires creating a new one, and assignment then points the variable to the new object.
Objects of classes you define are mutable and so your Pair instance can be modified by any function it is passed into -- that is, attributes may be added, deleted, or reassigned to other objects. None of these things will re-bind any of the names pointing to your object, so all the names that currently point to it will "see" the changes.
Python does not copy anything when passing variables to a function. It is neither call-by-value nor call-by-reference, but of those two it is more similar to call-by-reference. You could think of it as "call-by-value, but the value is a reference".
If you pass a mutable object to a function, then modifying that object inside the function will affect the object everywhere it appears. (If you pass an immutable object to a function, like a string or an integer, then by definition you can't modify the object at all.)
The reason this isn't technically pass-by-reference is that you can rebind a name so that the name refers to something else entirely. (For names of immutable objects, this is the only thing you can do to them.) Rebinding a name that exists only inside a function doesn't affect any names that might exist outside the function.
In your first example with the Pair objects, you are modifying an object, so you see the effects outside of the function.
In your second example, you are not modifying any objects, you are just rebinding names to other objects (other integers in this case). baz is a name that points to an integer object (in Python, everything is an object, even integers) with a value of 2. When you pass baz to foo(x), the name x is created locally inside the foo function on the stack, and x is set to the pointer that was passed into the function -- the same pointer as baz. But x and baz are not the same thing, they only contain pointers to the same object. On the x = x+1 line, x is rebound to point to an integer object with a value of 3, and that pointer is what is returned from the function and used to bind the integer object to y.
If you rewrote your first example to explicitly create a new Pair object inside your function based on the information from the Pair object passed into it (whether this is a copy you then modify, or if you make a constructor that modifies the data on construction) then your function would not have the side-effect of modifying the object that was passed in.
Edit: By the way, in Python you shouldn't use 0 as a placeholder to mean "I don't have a value" -- use None. And likewise you shouldn't use 0 to mean False, like you seem to be doing in flag. But all of 0, None and False evaluate to False in boolean expressions, so no matter which of those you use, you can say things like if not flag instead of if flag == 0.
I suggest that you forget about implementing a linked list, and simply use an instance of a Python list. If you need something other than the default Python list, maybe you can use something from a Python module such as collections.
A Python loop to follow the links in a linked list will run at Python interpreter speed, which is to say, slowly. If you simply use the built-in list class, your list operations will happen in Python's C code, and you will gain speed.
If you need something like a list but with fast insertion and fast deletion, can you make a dict work? If there is some sort of ID value (string or integer or whatever) that can be used to impose an ordering on your values, you could just use that as a key value and gain lightning fast insert and delete of values. Then if you need to extract values in order, you can use the dict.keys() method function to get a list of key values and use that.
But if you really need linked lists, I suggest you find code written and debugged by someone else, and adapt it to your needs. Google search for "python linked list recipe" or "python linked list module".
I'm going to throw in a slightly complicating factor:
>>> def foo(x):
... x *= 2
... return x
...
Define a slightly different function using a method I know is supported for numbers, lists, and strings.
First, call it with strings:
>>> baz = "hello"
>>> y = foo(baz)
>>> y
'hellohello'
>>> baz
'hello'
Next, call it with lists:
>>> baz=[1,2,2]
>>> y = foo(baz)
>>> y
[1, 2, 2, 1, 2, 2]
>>> baz
[1, 2, 2, 1, 2, 2]
>>>
With strings, the argument isn't modified. With lists, the argument is modified.
If it were me, I'd avoid modifying arguments within methods.