I\'m new to python.
I have a question about accessing attribute in class
t1.py
#!/usr/bin/python
import t2
class A:
flag = False
if __n
You can find this out yourself:
#!/usr/bin/python
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
logger.debug('t1 has started')
logger.debug('t2 is being imported')
import t2
logger.debug('A is being "compiled"')
class A:
flag = False
logger.debug('ID A: %r', id(A))
logger.debug('ID A.flag %r', id(A.flag))
logger.debug('What is __name__? %r', __name__)
if __name__ == "__main__":
logger.debug('__name__ was "__main__"')
logger.debug('Calling t2.f()')
t2.f()
logger.debug('t2.f() was called')
logger.debug('ID A.flag: %r', id(A.flag))
print(A.flag)
#!/usr/bin/python
import logging
logger = logging.getLogger(__name__)
logger.debug('t2 is being imported')
logger.debug('t2 is now importing t1')
import t1
def f():
logger.debug('f is being called')
t1.A.flag = True
logger.debug('ID t1: %r', id(t1))
logger.debug('ID t1.A: %r', id(t1.A))
logger.debug('ID t1.A.flag: %r', id(t1.A.flag))
print(t1.A.flag)
I'm splitting this up with comments
DEBUG:__main__:t1 has started
DEBUG:__main__:t2 is being imported
DEBUG:t2:t2 is being imported
DEBUG:t2:t2 is now importing t1
As you can see, the first time around (as others have mentioned) t1
actually has the name of __main__
. It tries importing t2
, but immediately t2
tries importing t1
.
DEBUG:t1:t1 has started
DEBUG:t1:t2 is being imported
You can see that none of the t2
logging statements run. That's because Python caches imported modules, so it first looks in the cache for t2
and says, "Ahah! I've already imported this guy, I just need to return it. Here you go, then!"
DEBUG:t1:A is being "compiled"
DEBUG:t1:ID A: 140377934341704
DEBUG:t1:ID A.flag 4312040768
DEBUG:t1:What is __name__? 't1'
So, you'll notice that now it has made its way through importing t1
. And t2
DEBUG:t2:t2 is done being imported
Execution continues back in the __main__
t1
DEBUG:__main__:A is being "compiled"
DEBUG:__main__:ID A: 140377934344360
DEBUG:__main__:ID A.flag 4312040768
Notice that the id
for this A
and A.flag
are different!
DEBUG:__main__:What is __name__? '__main__'
DEBUG:__main__:__name__ was "__main__"
DEBUG:__main__:Calling t2.f()
DEBUG:t2:f is being called
DEBUG:t2:ID t1: 4317998840
DEBUG:t2:ID t1.A: 140377934341704
DEBUG:t2:ID t1.A.flag: 4312040736
Notice again, that these id
s match t1.A
's, and not __main__.A
s.
True
DEBUG:__main__:t2.f() was called
DEBUG:__main__:ID A.flag: 4312040768
False
When you do
./t1.py
you're executing the t1.py
file, but it's not executed as the t1
module. It's considered to be the __main__
module. (This is what that if __name__ == '__main__'
line checks for.) That means that when this line:
import t1
in t2.py
tries to import t1
, Python starts executing the t1.py
file again to create the t1
module. You end up with two versions of the A
class, one being __main__.A
and one being t1.A
. The modification to t1.A
doesn't do anything to __main__.A
, because even though they came from the same code in the same file, they're not the same class.
Yeah, I can see how this can be a little confusing but it is basically a question of namespaces along with the distinction that the __main__
namespace is not considered as part of the list of imported modules. This allows the file that is the point of execution (and thus occupying the __main__
namespace) to also be imported as a module. On the other hand, if the same module is imported more than once, the interpreter will simply let all the different imports point to the same memory location
Because of this, in the code you are showing above, you actually have two distinct versions of A
: you have __main__.A
and you have __main__.t2.t1.A
. The second one comes about because __main__
is importing t2
which in turn is importing t1
as a module.
When you are running t2.f()
, you are setting __main__.t2.t1.A.flag = True
and then printing it. Subsequently, when you call print(A.flag)
, you are printing the value in __main__.A.flag
, which was never changed.
I hope that makes at least a little sense.
A friend of mine always said that computer science is an experimental science. Let's invoke the debugger.
I add a pdb.set_trace()
to the execution and t1.py
now looks like this:
#!/usr/bin/python
import t2
class A:
flag = False
if __name__ == "__main__":
import pdb; pdb.set_trace()
t2.f()
print(A.flag)
And this is what we get:
$ python t1.py
> /Users/martin/git/temp/t1.py(9)<module>()
-> t2.f()
(Pdb) A
<class __main__.A at 0x10ec9ba78>
(Pdb) t2.t1.A
<class t1.A at 0x10ec9ba10>
(Pdb)
Please note that the A
have separate memory locations associated.
They are indeed two different objects (explained very well in user2357112's answer). If you want t2
to use the same object, you need to tell Python that you are actually importing the same module that is importing t2
. To do that, import __main__
instead:
import __main__
def f():
__main__.A.flag = True
print(__main__.A.flag)