模块:__name__ == ‘__main__’、搜索路径和包 +习题复习

##模块!模块!
            (上一节课介绍了模块的作用以及用法,我们知道模块的主要作用是封装、组织Python的代码:当代码量非常大的时候,我们可以有组织、有纪律的根据不同的功能将代码分割为不同的模块,这样,每个模块之间互相就是分隔开的、独立开的,因为代码是分开了容易阅读和测试,人们都是更愿意去阅读和测试一小段代码,而不是一来就劈头盖脸把整个程序从头到尾的读起。

            模块的第二个重要的特性就是实现代码的重用,比如说你写了一段发送邮件的代码,多次调试、优化之后发现这段代码非常棒了,那你可以将这段代码封装成一个独立的模块,那以后在任何程序需要发送邮件的时候,只要导入这个模块,调用相关的函数就可以实现了,而不是说每一次都重复写相同的代码。这就是代码的重用)

       ※if __name__ == ‘__main__’

            (相信大部分人在读别人的Python代码的时候,都会看到这么一句代码,但是却不知道有什么用)

            (举个上节课温度的例子,我们在写模块的时候,一般我们在写了一个模块之后,我们会单独对这个模块进行测试,因为一个大程序会有非常多,成千上万个模块,那你应该每个模块独立写完之后,在后面写一个独立的 test(),对这个模块的功能进行测试,而不是组装起来才测试,那就很难调试了。对于这个温度转换这个模块,我们这里的测试就是对前面两个函数进行调用,如果正确,那就OK了)
在这里插入图片描述
在这里插入图片描述
            (测试没问题后,然后我们在 calc.py 这段源代码里面调用这个模块的话,如下:Python就不自觉的把模块中的测试代码也给打印出来了)
在这里插入图片描述
            (避免这种情况的关键在于让Python知道该模块是作为程序运行还是导入到其他程序中,为了实现这一点,你就可以使用 __name__变量,
            如果是在主程序里面使用这个 __name__变量的话,那得到的是个"__main__")

            如果是在模块中调用 这个 __name__变量的话,那得到的就是这个模块的名字。
            在这里插入图片描述
            这样的话,你就不难理解这个 if __name__ == ‘__main__’ 这句代码的意思了。所以在上面的模块的测试文件中,需要这样改写:
在这里插入图片描述
            也就是说,只有在直接运行该模块代码时(也就是测试模块的时候),__name__ 才等于"__main__",这时才运行test(),打印测试结果,当调用该模块时, __name__ 是等于"模块名"的,就不会打印测试结果了。

       ※搜索路径
            Python模块的导入需要一个路径搜索的过程,也就是说,你导入一个叫做 hello 的模块,那么Python会在预定义好的搜索路径里边找一个叫做 hello.py 的模块文件,如果有,则导入模块,如果没有,则导入失败,而这个搜索路径呢,事实上就是一个列表,一组目录,我们可以 sys 模块中的 path 变量把它显示出来:
在这里插入图片描述
            (如上所示,看到的是一个列表,列表里边有多个字符串,也就是说Python会从上面的路径中一个一个的去搜索有没有相关的模块,如果从其中一个找到就导入,如果找不到就拜拜,显示导入失败,需要注意的是,不同的系统显示的路径是不一样的,最佳的存放模块的位置是…\lib\site-packages,这个文件夹本来就是设置类存放模块的,放在其他也可以找到,但是一般推荐放在这个文件夹里边)

            (另外按照这个逻辑来说,我们只需要告诉Python你的模块文件在哪里找,Python在导入模块的时候就可以正确找到他,如下:我要导入D盘下一个文件夹里边的模块,直接import 模块名字是不行的,因为不在python的搜索路径范围中)
在这里插入图片描述
            那我们可以把他加到我们的搜索路径中去
在这里插入图片描述
            (这时候再来进行导入就可以了)
在这里插入图片描述
       ※包(package)
            (在实际开发中,一个大型的系统,有成千上万个Python模块很正常的,那么使用模块定义Python的功能还是远远不够的,因为如果你把这些模块全部放在一起,那你想想看,成千上万个文件放在一个文件夹是什么情况,会非常乱,非常糟糕,而且还有命名冲突的可能,因此Python中也出现了包的概念,什么是包呢,事实上就像我们刚才做的,把模块分门别类的放到不同的文件夹,然后把各个文件夹的位置告诉Python。那其实包的做法更为简洁,创建一个包也非常简单,步骤如下:)

         1、创建一个文件夹,用于存放相关的模块,文件夹的名字即包的名字;
            (如下,创建好后,把模块放到M1文件夹内)
在这里插入图片描述
         2、在文件夹中创建一个__init__.py的模块文件,内容可以为空;
在这里插入图片描述
            (这步中,必须在包目录下创建一个__init__.py的模块,你可以是一个空文件,但一定要创建这个文件,因为这是Python的规定,用来告诉Python,把这个文件夹(这个目录)当做一个包来管理。)

         3、将相关的模块放入文件夹中

            (接下来导入包的模块。如下:)
在这里插入图片描述

##温故知新之习题
           0. __name__ 属性的含义是什么?
           答:所有模块都有一个 __name__ 属性,__name__ 的值取决于如何应用模块,在作为独立程序运行的时候,__name__ 属性的值是 ‘__main__’,而作为模块导入的时候,这个值就是该模块的名字了。

            1. 什么时候 __name__ 属性的值是 “__main__”?
           答:模块在作为独立程序运行的时候,__name__ 属性的值是 ‘__main__’

            2. 如果获得当前 Python 的搜索路径?
           答:

>>> import sys
>>> sys.path
>['', '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 任何一个文件,都会报错,请改正程序。
           注:这道题原理跟上一节课的课后作业(测试题 4、5)类似,如果上节课你搞懂了,这道题应该可以想出解决方案,不要轻易看答案,除非你已经抓破头皮……

# 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()

            1. 下边是一个 Python 项目的基本结构,请你合理组织它们,便于维护和使用。
在这里插入图片描述
           答:通过将相关的模块组织成包,使项目结构更为完善和合理。从而增强代码的可维护性和实用性。

           以下提供一个可供参考的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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值