鱼C论坛

 找回密码
 立即注册
查看: 1605|回复: 14

关于if __name__ == "__main__"的疑问

[复制链接]
发表于 2020-3-26 16:45:25 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 kejun0566 于 2020-3-26 17:12 编辑

第051讲 课后作业 第0题。入口:https://fishc.com.cn/thread-65706-1-1.html

执行下边 a.py 或 b.py 任何一个文件,都会报错
# a.py
import b

def x():
    print('x')

b.y()

# b.py
import a

def y():
    print('y')

a.x()

执行 b.py 引发下边异常:
>>> 
Traceback (most recent call last):
  File "/Users/FishC/Desktop/b.py", line 1, in <module>
    import a
  File "/Users/FishC/Desktop/a.py", line 1, in <module>
    import b
  File "/Users/FishC/Desktop/b.py", line 6, in <module>
    a.x()
AttributeError: 'module' object has no attribute 'x'

小甲鱼的答案:
因为在执行 b.py 的加载过程中,需要创建新的模块对象 b,然后执行 b.py 对应的字节码。当遇到第一条语句(import a)的时候,Python 会转而去导入 a.py 并生成模块对象 a。同样遇到第一条语句(import b)的时候,Python 就跑去导入模块 b,此时发现 b 模块已经导入(在 sys.modules 中存在),继而执行 b 模块的字节码,当执行到 a.x() 的时候,由于模块 a 此时并未完全导入,所以抛出 AttributeError 异常。
怕有些鱼油可能看不懂,小甲鱼给大家整理下,看 Python 是如何被当成猴子耍的:
执行 b.py -> import a -> 查找 a 模块 -> 未发现 a 模块对象 -> 导入 a.py -> import b -> 查找 b 模块 -> 发现 b 模块对象 -> 接着往下执行字节码(import a 已执行过,Python 有机制确保不重复导入,因而不会再执行) -> a.x() -> 在 a 模块中找不到 x(),因为 a 还没有被完全导入嘛……
好了,解决的方案也很简单,用这节课的知识,就是使用 if __name__ == "__main__" 来确保 Python 不要在导入的过程中调用不该调用的函数。
# a.py
import b

def x():
    print('x')

if __name__ == "__main__":
    b.y()

# b.py
import a

def y():
    print('y')

if __name__ == "__main__":
    a.x()

我有点不明白,只是加了这句代码,并没有改变原有的调用顺序啊,不应该还是这样吗?:执行 b.py -> import a -> 查找 a 模块 -> 未发现 a 模块对象 -> 导入 a.py -> import b -> 查找 b 模块 -> 发现 b 模块对象 -> 接着往下执行字节码(import a 已执行过,Python 有机制确保不重复导入,因而不会再执行) -> a.x() -> 在 a 模块中找不到 x()

为什么就没问题了呢


然后我又改了下代码,只在a.py里加入 if __name__ == "__main__":
# a.py
import b

def x():
    print('x')

if __name__ == "__main__":
    b.y()

# b.py
import a

def y():
    print('y')

a.x()
然后执行 a.py,运行结果如下,也是正常的:
x
y
这个应该完全没有改变任何意思啊,在主程序里执行 代码 b.y(),应该不管加不加那句,这句代码都会被执行啊,为什么加了那句代码,就正常了呢,就不报错了呢?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-3-26 16:54:08 | 显示全部楼层
不不不,你应该还没有彻底理解这段代码的含义。
如果是被外部导入的,就不会运行a.x()了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-3-26 18:21:29 | 显示全部楼层
qiuyouzhi 发表于 2020-3-26 16:54
不不不,你应该还没有彻底理解这段代码的含义。
如果是被外部导入的,就不会运行a.x()了

不太明白,然后你看下这段,应该怎么解释呢?
微信截图_20200326181732.png
实在无法理解
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-26 18:28:45 | 显示全部楼层
kejun0566 发表于 2020-3-26 18:21
不太明白,然后你看下这段,应该怎么解释呢?

实在无法理解

你不理解的地方是加了if __name__ == "__main__"没有区别是吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-3-26 18:49:56 | 显示全部楼层
qiuyouzhi 发表于 2020-3-26 18:28
你不理解的地方是加了if __name__ == "__main__"没有区别是吗?
# a.py
import b

def x():
    print('x')

if __name__ == "__main__":
    b.y()

这个地方 加了if __name__ == "__main__" ,跟不加这段代码,不是都会执行下面的 b.y()吗?那为什么加了就没问题了呢?麻烦您告知一下,谢谢了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-26 19:08:01 | 显示全部楼层
kejun0566 发表于 2020-3-26 18:49
这个地方 加了if __name__ == "__main__" ,跟不加这段代码,不是都会执行下面的 b.y()吗?那为什么 ...

if __name__ == "__main__" 限定了只有在执行 a.py(不是导入 a.py)时调用 b.y()
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-3-26 19:15:04 | 显示全部楼层
zltzlt 发表于 2020-3-26 19:08
if __name__ == "__main__" 限定了只有在执行 a.py(不是导入 a.py)时调用 b.y()

没有导入啊,就是执行 a.py 啊
# a.py
import b

def x():
    print('x')

if __name__ == "__main__":
    b.y()

# b.py
import a

def y():
    print('y')
a.x()

在a.py 里加了这个代码
if __name__ == "__main__":
    b.y()
然后执行 a.py
按道理说,不是加 或者 不加,效果都是一样的吗?为什么加了就没问题,不加就会报错呢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-26 20:05:44 | 显示全部楼层
kejun0566 发表于 2020-3-26 19:15
没有导入啊,就是执行 a.py 啊

导入了 b 模块,而 b 模块又导入了 a 模块。这时导入 a 模块不会执行 b.y()
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-3-27 00:08:21 | 显示全部楼层
zltzlt 发表于 2020-3-26 20:05
导入了 b 模块,而 b 模块又导入了 a 模块。这时导入 a 模块不会执行 b.y()

执行a.py输出结果显示的是:
x
y

很明显,已经执行了 b.y()吧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-27 07:57:08 | 显示全部楼层
kejun0566 发表于 2020-3-27 00:08
执行a.py输出结果显示的是:

第一次执行 a.py 执行了 b.y(),导入了 b 模块,而 b 模块又导入了 a 模块。这时导入 a 模块不会执行 b.y()
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-3-27 12:38:36 | 显示全部楼层
zltzlt 发表于 2020-3-27 07:57
第一次执行 a.py 执行了 b.y(),导入了 b 模块,而 b 模块又导入了 a 模块。这时导入 a 模块不会执行 b.y ...

看了半天,模拟了半天,还是无法理解,能麻烦您详细说说吗,麻烦您了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-27 15:11:06 | 显示全部楼层
本帖最后由 Hoiste 于 2020-3-27 15:57 编辑

最开始那个的出错原因应该明白吧?
那我从加了if __name__ == '__main__':的代码开始解释,过程是这样的。
执行b.py —— import a —— 代码导入a.py并执行,遇到了import b —— 导入b.py并执行,这时因为内部机制不会再import a了,而是一路执行到if __name__ == '__main__':这句话 —— 因为此时依然是a模块在导入b模块内容的过程,所以是a模块在读b程序,if条件不成立,不会执行下面的函数 —— 回到a代码继续导入,执行到if __name__ == '__main__':同样不成立,不执行—— a模块导入完毕,回到b.py继续运行,这时if __name__ == '__main__':已经是b.py本身在执行了,而a模块也完全导入,所以a.x()可以执行,打印x。

这里的关键思路是你的import模块还没有结束的过程。这里有个链接可以参考一下:
https://www.cnblogs.com/chenhuabin/p/10118199.html
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-27 15:35:12 | 显示全部楼层
本帖最后由 Hoiste 于 2020-3-27 15:56 编辑

犯浑了,图解释错的,我重新弄一下。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-27 16:02:41 | 显示全部楼层
改好图解了,看得懂就看,看不懂就继续看23333
无标题.png
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-1-25 02:37

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表