I searched all over and could not come up with a reasonable search query to produce helpful results. I'll try to explain this with a simple example (that is tested).
Suppose I have some small custom Python library that contains just the following private class and public instance of it:
#!/usr/bin/env python
class _MyClass(object):
def __init__(self):
self.val = "Default"
my_instance = _MyClass()
Now, I also have two other python files ('file_a' and 'file_b') that will end up importing this instance from my library as seen below.
The full code in 'file_a':
#!/usr/bin/env python
from my_lib import my_instance
my_instance.val = "File A was here!"
import file_b
file_b.check_val()
The full code in 'file_b':
#!/usr/bin/env python
from my_lib import my_instance
def check_val():
print "From 'file_b', my_instance.val is: {}".format(my_instance.val)
The resulting output, if I only execute 'file_a' within a directory that also contains 'file_b' and 'my_lib', is this:
From 'file_b', my_instance.val is: File A was here!
Can someone explain to me how 'file_b' is able to access the same exact instance as 'file_a' in my example? Does this have to do with how the value being set in 'file_a' is global?
By the way, I do know I can just make 'MyClass' public again and instantiate it whenever a unique instance is needed in either 'file_a' or 'file_b', but the main reason I am posting this question is to wrap my head around this specific concept.
There are two things you need to understand here:
Python caches module imports to improve performance, this happens even when you do from foo import bar
. The module object gets stored in sys.modules
.
Hence, in your case both file_a
and file_b
are accessing same module object my_lib
and same instance my_instance
.
In Python variable assignment is basically adding a new reference to the same object, this is true for imports as well.
from my_lib import my_instance
is basically
import my_lib
my_instance = my_lib.my_instance
del my_lib
Now as we modify this instance in file_a
, we have basically modified the instance in my_lib
, and file_b
will also see this change.
You can modify file_a
and file_b
to verify this.
file_a
:
#!/usr/bin/env python
from my_lib import my_instance
my_instance.val = "File A was here!"
print "Inside file_a"
import sys
print id(sys.modules['my_lib']), sys.modules['my_lib'].my_instance, my_instance
import file_b
file_b.check_val()
file_b
:
#!/usr/bin/env python
from my_lib import my_instance
print "Inside file_b"
import sys
print id(sys.modules['my_lib']), sys.modules['my_lib'].my_instance, my_instance
def check_val():
print "From 'file_b', my_instance.val is: {}".format(my_instance.val)
Output(check the object IDs):
>>> %run file_a.py
Inside file_a
4396461816 <my_lib._MyClass object at 0x106158ad0> <my_lib._MyClass object at 0x106158ad0>
Inside file_b
4396461816 <my_lib._MyClass object at 0x106158ad0> <my_lib._MyClass object at 0x106158ad0>
From 'file_b', my_instance.val is: File A was here!