(标答出处: 鱼C论坛)
《零基础入门学习Python》
本节知识点:
(一)if __name__ == '__main__' :
避免这种情况的关键在于让Python知道该模块是作为程序运行还是导入到其他程序中,为了实现这一点,你就需要使用 __name__变量,
如果是在主程序里面使用这个 __name__变量的话,那得到的是个"__main__"
如果是在模块中调用 这个 __name__变量的话,那得到的就是这个模块的名字。
>>> __name__
'__main__'
>>>
>>> tc.__name__
'TemperatureConversion'
这样的话,你就不难理解这个 if __name__ == '__main__' 这句代码的意思了。
所以在上面的模块的测试文件中,需要这样改写:
def c2f(cel):
fah = cel * 1.8 + 32
return fah
def f2c(fah):
cel = (fah - 32) / 1.8
return cel
def test():
print("测试,0摄氏度 = %.2f华氏度"%c2f(0))
print("测试,0华氏度 = %.2f摄氏度"%f2c(0))
if __name__ == "__main__":
test()
也就是说,只有在直接运行该模块代码时(也就是测试模块的时候),__name__ 才等于"__main__",这时才运行test(),打印测试结果,
当调用该模块时, __name__ 是等于"模块名"的,就不会打印测试结果了。
(二)搜索路径:
Python模块的导入需要一个路径搜索的过程,也就是说,你导入一个叫做 hello 的模块,Python会在预定义好的搜索路径里面找一个叫做
hello.py 的模块文件,如果有,则导入模块,如果没有,则导入失败,而这个搜索路径呢,就是一个列表,一组目录,我们可以 sys 模块
中的 path 变量把它显示出来:
>>> import sys
>>> sys.path
['D:\\ProgramFiles\\Anaconda3\\Lib\\idlelib',
'D:\\ProgramFiles\\Anaconda3\\python35.zip',
'D:\\ProgramFiles\\Anaconda3\\DLLs',
'D:\\ProgramFiles\\Anaconda3\\lib',
'D:\\ProgramFiles\\Anaconda3',
'D:\\ProgramFiles\\Anaconda3\\lib\\site-packages',
'D:\\ProgramFiles\\Anaconda3\\lib\\site-packages\\Sphinx-1.4.6-py3.5.egg',
'D:\\ProgramFiles\\Anaconda3\\lib\\site-packages\\win32',
'D:\\ProgramFiles\\Anaconda3\\lib\\site-packages\\win32\\lib',
'D:\\ProgramFiles\\Anaconda3\\lib\\site-packages\\Pythonwin',
'D:\\ProgramFiles\\Anaconda3\\lib\\site-packages\\setuptools-27.2.0-py3.5.egg']
sys 是与系统相关的模块,Python 会从上面的路径中一个一个的去搜索有没有相关的模块。这里需要解释的是,不同的系统的 sys.path 显
示的路径是不一样的,这里最佳的存放模块的位置是 '...\\lib\\site-packages',该文件夹本来就是设置类存放模块的。
另外,按照这里逻辑来说,你只需要告诉 Python 你的模块文件在哪里找,Python在导入模块的时候就可以正确找到,例如:我们想把桌面上
的一个模块导入,我们直接导入的话,是找不到的,因为桌面的路径是不属于 sys.path 的搜索路径的,我们就可以把 桌面路径加到搜索
路径中去。
import sys
sys.path.append("C:\\Users\\XiangyangDai\\Desktop")
(三)包(package):
Python中也出现了包的概念,什么是包呢,其实就像我们刚才做的,把模块分门别类的放到不同的文件夹,然后把各个文件夹的位置告诉
Python。但是包的做法更加简洁,创建一个包也非常简单,步骤如下:
在第2步中,必须在包目录下创建一个__init__.py的模块,你可以是一个空文件,但是必须要有这个文件,因为这是Python的规定,用来告
诉Python,把这个文件夹(这个目录)当做一个包来管理。
接下来,要导入包的模块,怎么导?其实也很简单,就是使用 包名.模块名 来导入就可以了
import sys
sys.path.append("C:\\Users\\XiangyangDai\\Desktop")
import M1.TemperatureConversion as tc
print("32摄氏度 = %.2f华氏度"%tc.c2f(32))
print("99华氏度 = %.2f摄氏度"%tc.f2c(99))
>>>
=============== RESTART: C:\Users\XiangyangDai\Desktop\calc.py ===============
32摄氏度 = 89.60华氏度
99华氏度 = 37.22摄氏度
测试题(笔试,不能上机哦~):
答:所有模块都有一个 name 属性,name 的值取决于如何应用模块,在作为独立程序运行的时候,name 属性的值是 ‘main’,而作为模块导入的时候,这个值就是该模块的名字了。
答:模块在作为独立程序运行的时候,name 属性的值是 ‘main’
答:导入 sys 模块 使用 sys.path 查询,最后输出的是路径的列表。
答:可以创建一个包(package),放在 site-packages 文件夹,因为它就是用来存放你的模块文件的。
答:是一个包,Python 把同类的模块放在一个文件夹中统一管理,这个文件夹称之为一个包。
urllib 是 Python 负责管理 URL 的包,用于访问网址(后边我们会讲到)。
答:看文件夹中是否有 init.py 文件。
必须在包文件夹中创建一个 init.py 的模块文件,内容可以为空。可以是一个空文件,也可以写一些初始化代码。这个是 Python 的规定,用来告诉 Python 将该目录当成一个包来处理。
动动手:
答:因为在执行 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()
答:通过将相关的模块组织成包,使项目结构更为完善和合理。从而增强代码的可维护性和实用性。
以下提供一个可供参考的Python项目结构(仅供参考,没有硬性规定):
|----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