Reputation: 43
I am trying to call a function passvalue
from another file named "File1" as module to the "Main File". I expect the value of x
in "Main File" to be 4 instead of 1 and the value of y
to be 3 instead of 2 after calling the function.
Question: How do I ensure the value from the module's function from "File1" is passed onto the "Main File"? For this case, x=4
and y=3
.
My thoughts: I tried using global value but it does not seem to work, return in this case is only going to return either x
or y
value back to the function itself which probably defeat the purpose.
Felt like I am missing out something simple but can't seem to get it.
def passvalue(a,b)
b=b+a
a=b+b
import File1
x=1
y=2
File1.passvalue(x,y)
print(x)
print(y)
Upvotes: 0
Views: 216
Reputation: 13898
There are multiple reasons it doesn't work:
First, objects assigned in a function are created locally. When you do a=...
and b=...
, a
and b
are local objects that you created within the function that assigned to the parameter values. Once the function exits, a
and b
no longer hold any relevance to code outside of the immediate function's scope.
Second, while objects are passed in reference in Python, what remains immutable are immutable. Since x
and y
are integers, they are immutable to change, i.e. each time you perform any operation on them, a new value is being assigned to the object instead of it changed.
To understand this, consider the following function:
def mod_lists(list_1, list_2, list_3):
print("obj ID of rlst_1 = {0}\n"
"obj ID of rlst_2 = {1}\n"
"obj ID of rlst_3 = {2}\n".format(id(rlst_1), id(rlst_2), id(rlst_3)))
print("Before change:\n"
"obj ID of list_1 = {0}\n"
"obj ID of list_2 = {1}\n"
"obj ID of list_3 = {2}\n".format(id(list_1), id(list_2), id(list_3)))
list_1.append("hello")
list_2 = list_1 + ["world"]
list_3 = list_1 + ["world"]
print("After change:\n"
"obj ID of list_1 = {0}\n"
"obj ID of list_2 = {1}\n"
"obj ID of list_3 = {2}\n".format(id(list_1), id(list_2), id(list_3)))
return list_3
Now consider I have three list
s I want to pass:
rlst_1 = list()
rlst_2 = list()
rlst_3 = list()
And I call the function as follows:
rlst_3 = mod_lists(rlst_1, rlst_2, rlst_3)
Now you might expect rlst_1 = ['hello']
, rlst_2 = ['hello', 'world']
and rlst_3 = ['hello', 'world']
, but that is wrong. If you ran it, you'll notice rlst_2
will actually be an empty list
(unchanged).
So what makes rlst_1
and rlst_3
changes? Let's take a look at the object IDs printed out and compare:
# NOTE: You will see different numbers on your system.
obj ID of rlst_1 = 52178816
obj ID of rlst_2 = 52337240
obj ID of rlst_3 = 51607312
Before change:
obj ID of list_1 = 52178816
obj ID of list_2 = 52337240
obj ID of list_3 = 51607312
After change:
obj ID of list_1 = 52178816
obj ID of list_2 = 52336920
obj ID of list_3 = 52336840
Before any changes were made in the function, you can see the object IDs are exactly the same respectively, that means list_1
is an exact reference of rlst_1
, etc. Now after the changes were done is where you notice the changes. You can see that list_2
and list_3
now have a different object ID. Why is that? That's because in the lines list_2=...
and list_3=...
you are effectively reassigning both objects to a new reference, which is list_1 + ['world']
. You might also wonder why they both have a different ID because the value should be the same. While list_1
is the same reference, each ['world']
is a new instance of the list
object containing the word "world"
as an item, so they are different objects even though they have the same values.
Why doesn't list_1
's object reference get affected though? That's because when you call the append
function on list_1
, it doesn't reassign but is changing the object in reference, appending the value "hello"
into the same object.
Now after the function call, when you print the rlst
s, you will see:
# rlst_1
# ['hello']
# rlst_2
# []
# rlst_3
# ['hello', 'world']
rlst_1
is changed, as expected, because the same object in reference was modified. rlst_2
is unchanged, because even though list_2
was reassigned a new list, it was a local object created within the function, and lost after function exits.
Why did rlst_3
get updated? You might think it's updated, but it's actually a NEW object with the same name. Note the last part of the function returns the locally created list_3
which has the value of list_1 + ['world']
. So the function call evaluates as follows:
rlst_3 = mod_lists(rlst_1, rlst_2, rlst_3)
(local) list_1 = ['hello']
(local) list_3 = list_1 + ['world']
(local) list_3 = ['hello', 'world']
rlst_3 = list_3
rlst_3 = ['hello', 'world']
If that's still confusing, run a id(rlst_3)
, and you'll see 52336840
, which is exactly the object ID of the locally created list_3
(again, you'll probably see a different number, but the id(rlst_3)
will always equal id(list_3)
).
Applying this logic, now you can understand why it is impossible to pass immutable integers in reference and hoping to modify them in the function. The only way you can change the outside object is reassign them to the newly created local objects being returned by the function.
This answer is obviously much more long winded than Stephen Rauch's, but it gives a little bit more background to why it doesn't work.
Upvotes: 1
Reputation: 49842
You need to return
the values like:
def passvalue(a,b)
b=b+a
a=b+b
return a, b
This returns a tuple
. The tuple
can the unpacked like:
# Main File
import File1
x=1
y=2
x, y = File1.passvalue(x,y)
print(x)
print(y)
Upvotes: 2