Python——__name__属性、搜索路径和包

测试题(笔试,不能上机哦~):
0. __name__ 属性的含义是什么?
1. 什么时候 __name__ 属性的值是 "__main__"?
2. 如果获得当前 Python 的搜索路径?
3. 如果你不想将相关的模块文件放在当前文件夹内,那最好的选择是?
4. 如果你见到 import urllib.request 语句,那么这个 urllib 是什么?
5. Python 如何区分一个文件夹是普通文件夹还是包?
动动手(一定要自己动手试试哦~):
0. 执行下边 a.py 或 b.py 任何一个文件,都会报错,请改正程序。
注:这道题原理跟上一节课的课后作业(测试题 4、5)类似,如果上节课你搞懂了,这道题应该可以想出解决方案,不要轻易看答案,除非你已经抓破头皮……

  1. # a.py
  2. import b
  3.  
  4. def x():
  5.     print('x')
  6.  
  7. b.y()
  8.  
  9. # b.py
  10. import a
  11.  
  12. def y():
  13.     print('y')
  14.  
  15. a.x()
  16.  
  17. 执行 b.py 引发下边异常:
  18. >>> 
  19. Traceback (most recent call last):
  20.   File "/Users/FishC/Desktop/b.py", line 1, in <module>
  21.     import a
  22.   File "/Users/FishC/Desktop/a.py", line 1, in <module>
  23.     import b
  24.   File "/Users/FishC/Desktop/b.py", line 6, in <module>
  25.     a.x()
  26. AttributeError: 'module' object has no attribute 'x'

复制代码



1. 下边是一个 Python 项目的基本结构,请你合理组织它们,便于维护和使用。
Python——__name__属性、搜索路径和包 鱼C大项目.zip (3.87 KB, 下载次数: 844) 

Python——__name__属性、搜索路径和包

图一时之快先看答案,您将失去一次锻炼的机会!
请先自己动手,再回复查看参考答案!
测试题答案:
0. __name__ 属性的含义是什么?
答:所有模块都有一个 __name__ 属性,__name__ 的值取决于如何应用模块,在作为独立程序运行的时候,__name__ 属性的值是 '__main__',而作为模块导入的时候,这个值就是该模块的名字了。
1. 什么时候 __name__ 属性的值是 "__main__"?
答:请参考上一题答案。
2. 如果获得当前 Python 的搜索路径?
答:我们可以通过 sys 模块中的 path 变量显示出来(不同的机器上显示的路径信息可能不一样)。

  1. >>> import sys
  2. >>> sys.path
  3. ['', 'C:\\Python34\\Lib\\idlelib', 'C:\\WINDOWS\\SYSTEM32\\python34.zip', 'C:\\Python34\\DLLs', 'C:\\Python34\\lib', 'C:\\Python34', 'C:\\Python34\\lib\\site-packages']

复制代码



3. 如果你不想将相关的模块文件放在当前文件夹内,那最好的选择是?
答:放在 site-packages 文件夹,因为它就是用来存放你的模块文件的。
4. 如果你见到 import urllib.request 语句,那么这个 urllib 是什么?
答:是一个包,Python 把同类的模块放在一个文件夹中统一管理,这个文件夹称之为一个包。
urllib 是 Python 负责管理 URL 的包,用于访问网址(后边我们会讲到)。
5. Python 如何区分一个文件夹是普通文件夹还是包?
答:看文件夹中是否有 __init__.py 文件。
必须在包文件夹中创建一个 __init__.py 的模块文件,内容可以为空。可以是一个空文件,也可以写一些初始化代码。这个是 Python 的规定,用来告诉 Python 将该目录当成一个包来处理。


动动手答案:
0. 执行下边 a.py 或 b.py 任何一个文件,都会报错,请改正程序。
答:因为在执行 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 不要在导入的过程中调用不该调用的函数。
所以应该这么写:

  1. # a.py
  2. import b
  3.  
  4. def x():
  5.     print('x')
  6.  
  7. if __name__ == "__main__":
  8.     b.y()
  9.  
  10. # b.py
  11. import a
  12.  
  13. def y():
  14.     print('y')
  15.  
  16. if __name__ == "__main__":
  17.     a.x()

复制代码


1. 下边是一个 Python 项目的基本结构,请你合理组织它们,便于维护和使用。
答:通过将相关的模块组织成包,使项目结构更为完善和合理。从而增强代码的可维护性和实用性。
以下提供一个可供参考的Python项目结构(仅供参考,没有硬性规定):

鱼C大项目/
|----README/
|    |----readme.txt
|    |----LICENSE.txt
|    |----requirents.txt
|    |----setup.py
|----docs/
|    |----help.html
|    |----quickstart.html
|----test/
|    |----__init__.py
|    |----test_basic.py
|    |----test_advanced.py
|----package/
|    |----__init__.py
|    |----moduleA.py
|    |----moduleB.py
|    |----moduleC.py
|    |----static/
|    |    |----images/
|    |    |----sounds/
|----setup.py