|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
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,运行结果如下,也是正常的:
这个应该完全没有改变任何意思啊,在主程序里执行 代码 b.y(),应该不管加不加那句,这句代码都会被执行啊,为什么加了那句代码,就正常了呢,就不报错了呢? |
|