我是python的新手。
我有一个关于访问类
中的属性的问题t1.py
#!/usr/bin/python
import t2
class A:
flag = False
if __name__ == "__main__":
t2.f()
print(A.flag)
t2.py
#!/usr/bin/python
import t1
def f():
t1.A.flag = True
print(t1.A.flag)
执行结果:
# ./t1.py
True
False
我希望结果必须为True,True。
t1.py中的A.flag和t2.py中的t1.A.flag不同吗?
执行此代码时python中发生了什么?
谢谢。
答案 0 :(得分:2)
当你这样做时
./t1.py
您正在执行t1.py
文件,但它并未作为t1
模块执行。它被认为是__main__
模块。 (这是if __name__ == '__main__'
行检查的内容。)这意味着当这一行:
import t1
t2.py
中的尝试导入t1
,Python开始再次执行t1.py
文件 以创建t1
模块。您最终得到了A
类的两个版本,一个是__main__.A
,另一个是t1.A
。对t1.A
的修改对__main__.A
没有任何作用,因为即使它们来自同一文件中的相同代码,它们也不是同一个类。
答案 1 :(得分:0)
它们确实是两个不同的对象(在user2357112's answer中解释得非常好)。如果您希望t2
使用相同的对象,则需要告诉Python您实际上正在导入导入t2
的同一模块。为此,请改为导入__main__
:
import __main__
def f():
__main__.A.flag = True
print(__main__.A.flag)
答案 2 :(得分:0)
你可以自己找到它:
#!/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)
我用评论将其分开
DEBUG:__main__:t1 has started
DEBUG:__main__:t2 is being imported
DEBUG:t2:t2 is being imported
DEBUG:t2:t2 is now importing t1
正如您所看到的,第一次(正如其他人提到的那样)t1
实际上名称为__main__
。它会尝试导入t2
,但会立即t2
尝试导入t1
。
DEBUG:t1:t1 has started
DEBUG:t1:t2 is being imported
您可以看到没有t2
日志记录语句运行。那是因为Python缓存导入的模块,因此它首先在缓存中查找t2
并说:“啊哈!我已经导入了这个人,我只需要将它返回。然后你就去了!”
DEBUG:t1:A is being "compiled"
DEBUG:t1:ID A: 140377934341704
DEBUG:t1:ID A.flag 4312040768
DEBUG:t1:What is __name__? 't1'
所以,你会注意到它现在已经通过导入t1
。并t2
DEBUG:t2:t2 is done being imported
继续执行__main__
t1
DEBUG:__main__:A is being "compiled"
DEBUG:__main__:ID A: 140377934344360
DEBUG:__main__:ID A.flag 4312040768
请注意,此id
和A
的{{1}}不同!
A.flag
再次注意,这些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
匹配id
,而不是t1.A
。
__main__.A
答案 3 :(得分:-1)
是的,我可以看到这有点令人困惑,但它基本上是命名空间的问题,以及__main__
命名空间不被视为导入模块列表的一部分的区别。这允许作为执行点(因此占用__main__
命名空间)的文件也作为模块导入。另一方面,如果同一个模块被多次导入,解释器只会让所有不同的导入指向同一个内存位置
因此,在您上面显示的代码中,您实际上有两个不同版本的A
:您拥有__main__.A
并且您拥有__main__.t2.t1.A
。第二个问题是因为__main__
正在导入t2
,而t1
正在导入t2.f()
作为模块。
当您运行__main__.t2.t1.A.flag = True
时,您正在设置print(A.flag)
然后打印它。随后,当您致电__main__.A.flag
时,您将打印pdb.set_trace()
中未永久更改的值。
我希望这至少有点意义。
我的一位朋友总是说计算机科学是一门实验科学。 让我们调用调试器。
我在执行中添加t1.py
,#!/usr/bin/python
import t2
class A:
flag = False
if __name__ == "__main__":
import pdb; pdb.set_trace()
t2.f()
print(A.flag)
现在看起来像这样:
$ 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)
这就是我们得到的:
A
请注意,#define my_malloc_macro(size, ptr) do { \
ptr = malloc(size); \
if(!ptr) { \
printf("malloc failed\n"); \
return -1; \
} \
} while(0)
有相关的单独内存位置。