模块

1. 什么是模块

模块是一个包含所有你定义的函数和变量的文件,其后缀名是.py
你可以简单的理解成,一个.py文件就是一个模块

2.模块存在的意义

那些有着相似作用的函数,比如和时间相关的,和文件路径相关的,和系统环境相关的,他们所能处理的问题有着紧密的联系,把他们设计成一个模块,在使用的时候,便于查找,也便于维护。
这就好比,你家里的抽屉,里面存放的物品,大多数情况下都是按类别和用途分层存储的,这样,找物品的时候就比较的方便。
我们维护代码时,也采用这样的思路。以《文件读写》教程里的4.2 练习题为例,在这个练习题里我一共写了三个函数,他们分别是:

  1. get_file_lst
  2. get_program_line_count
  3. get_py_program_count

这其中函数get_file_lst非常具有通用性,它既可以在计算文件夹下所有python脚本代码行数这个事情上使用,也可以在其他场景下使用,函数的功能越是简单,越是有通用性。那么这样的函数,通常我们会把它单独的存放到一个模块里,这样,其他的模块就可以在需要的时候引用它。

3. import

为了向你演示如何引入其他模块为己所用,我将《文件读写》教程里的4.2 练习题的文件结构进行修改
utils.py文件的内容如下

  1. import os
  2. def get_file_lst(py_path, suffix):
  3. """
  4. 遍历指定文件目录下的所有指定类型文件
  5. :param py_path:
  6. :return:
  7. """
  8. file_lst = []
  9. for root, dirs, files in os.walk(py_path):
  10. for file in files:
  11. file_name = os.path.join(root, file)
  12. if file_name.endswith(suffix):
  13. file_lst.append(file_name)
  14. return file_lst

如何在program_count.py 文件中使用utils.py文件中的函数呢?使用import,直接导入utils模块,使用get_file_lst函数时,则需要用utils.get_file_lst这种方法来调用函数。

  1. import utils
  2. def get_program_line_count(file_name):
  3. """
  4. 返回单个py脚本的代码行数
  5. :param filename:
  6. :return:
  7. """
  8. # 存储代码行数
  9. count = 0
  10. with open(file_name, 'r', encoding='utf-8')as f:
  11. for line in f:
  12. line = line.strip()
  13. if not line:
  14. continue
  15. if line.startswith("#"):
  16. continue
  17. count += 1
  18. return count
  19. def get_py_program_count(py_path):
  20. # 获取指定目录下所有的python脚本
  21. file_lst = utils.get_file_lst(py_path, '.py')
  22. count = 0
  23. # 遍历列表,获取单个python脚本的代码行数
  24. for file_name in file_lst:
  25. count += get_program_line_count(file_name) # 累加代码函数
  26. return count # 返回代码总函数
  27. if __name__ == '__main__':
  28. py_path = '/Users/kwsy/PycharmProjects/pythonclass'
  29. print(get_py_program_count(py_path))

4. from … import …

import 会将整个模块的内容全部导入,但有时,我们不需要那么多,只需要其中一个两个就可以了
于是,我们也可以这样写

  1. from utils import get_file_lst
  2. def get_py_program_count(py_path):
  3. file_lst = get_file_lst(py_path, '.py')
  4. count = 0
  5. for file_name in file_lst:
  6. count += get_program_line_count(file_name)
  7. return count

如果你想全部导入,也可以写成from … import 的形式,表示全部导入。这种写法和import的区别在于,import一个模块A后,调用A里的函数是必须写成A.func的形式,而from … import … 的方法,就可以不用模块去调用方法了,可以直接调用函数

5. globals()

globals函数以字典的形式返回当前位置的全部全局变量
在一个模块中执行

  1. print(globals())

你会得到一个字典,包含了当前模块的全部全局变量,这里面有你定义的函数,全局变量,还有一些是系统自带的全局变量,例如name, file, doc

  • name 模块名称
  • file 当前脚本的绝对路径
  • doc 当前模块的注释
    1. '''
    2. 当前模块的注释说明
    3. '''
    4. def test():
    5. print("调用函数test")
    6. g_var = globals()
    7. print(g_var)
    8. print(__file__)
    9. print(__name__)
    10. print(__doc__)
    11. g_var['test']() # 可以调用test函数
    函数test 也是对象,而且是全局变量,g_var是字典,字符串 ‘test’ 作为key,其value就是函数test

if name == ‘main

  1. def func():
  2. print('ok')
  3. if __name__ == '__main__':
  4. func()

这种形式的代码,相信你已经见过很多,在脚本的末尾,出现一个if条件判断,这个if条件判断的作用是什么呢, name 事先并没有定义,为什么可以直接使用呢,它从哪里来? 回答这些问题,必须先了解模块属性

1. 模块属性

一个python脚本(以.py 结尾的文件)就是一个模块,模块自身有若干属性,其中比较常用的是如下两个

  1. name 模块的名称
  2. file 脚本的完整文件路径

在任意一个python脚本里,你都可以输出这两个属性

  1. print(__name__)
  2. print(__file__)

得到结果

  1. __main__
  2. /Users/zhangdongsheng/experiment/test/test.py

name 的值是 main ,这表示模块的名称是”main“, file 是文件的完整路径
虽然弄清楚了name 是怎么一回事,但也带来了新的疑问,明明name 就等于 main ,为何还要做if条件判断呢?显然是存在 name 不等于main 的情况。

2. 直接执行与其他模块引入

简单的功能,我们可以在一个python脚本里完成,但复杂的功能,我们会写多个python 脚本,比如下面的例子里,有两个脚本,一个是main.py ,做为整个程序的启动脚本,utils.py 提供一些辅助函数,供main.py使用
(1)utils.py

  1. def safe_division(a, b):
  2. if b == 0:
  3. return None
  4. return a/b
  5. print("utils 模块里的__name__ 值为:", __name__)

(2)main.py

  1. from utils import safe_division
  2. def func():
  3. value = input("输入两个整数,中间用空格分开:")
  4. arrs = value.split()
  5. a = int(arrs[0])
  6. b = int(arrs[1])
  7. result = safe_division(a, b)
  8. print(result)
  9. if __name__ == '__main__':
  10. func()

接下来,通过两步实验,来理解 name 在不同场景下的取值情况。
第一步,先来执行utils.py文件

  1. python utils.py

执行结果为

  1. utils 模块里的__name__ 值为: __main__

第二步,执行main.py

  1. python main.py

执行结果为

  1. utils 模块里的__name__ 值为: utils
  2. 输入两个整数,中间用空格分开:5 2
  3. 2.5

这里有一个现象,你必须理解其背后的原因,我们明明执行的main.py脚本,但是utils.py脚本里的代码也被执行了,这是因为在main.py脚本里引入了utils.py 这个模块,被引入的脚本里的代码会在引入时执行。
当utils.py 被其他脚本引入时,它的name 就不等于main, 而是等于utils,恰好是文件名称去掉.py 剩余的部分。
经过上面的实验,我们可以得出两个结论

  1. 当脚本被直接执行时,模块属性name 等于main
  2. 当脚本被其他模块引入时,模块属性name 等于脚本名称去掉.py 后剩余的部分

3、终极目的—-测试模块里函数
由于一个脚本被引入时,自身的代码会被执行,因此我们在每个脚本里都写上一段if name == ‘main‘: 如果你希望一些代码只有在脚本被直接执行时才执行,那么就把这些代码放入到if 语句块中,最常见的情形就是测试代码,下面我对utils.py 进行修改

  1. def safe_division(a, b):
  2. if b == 0:
  3. return None
  4. return a/b
  5. if __name__ == '__main__':
  6. print(safe_division(10, 5) == 2)
  7. print(safe_division(10, 0) == None)

我们写完一个函数后,不免要写一些测试的代码,而这些测试的代码我们不希望他们在utils.py被引入时执行,只有当我们主动执行utils.py 进行测试才执行这些测试代码

什么是pip,如何安装管理第三方模块

pip 是python标准库的管理工具,使用它可以安装管理第三方库,本篇教程一篇新手引导教程,通过本篇教程,你可以学会掌握以下几点技能

  1. 安装第三方库
  2. 在 Python Package Index (PyPI) 上查找第三方库
  3. 管理requirements.txt文件
  4. 卸载第三方库

    1. 安装第三方库

    python是一门自带电池的语言,它本身提供了非常丰富的标准库,同时,python又有着非常活跃的开源社区,在这里,人们实现并贡献了大量第三方库,这些第三方库是对python标准库的补充,那些优秀的第三方库经过一段时间发展后有可能成为标准库随python一同发布。
    下面是一个使用标准库的示例
    1. import json
    2. data = [1, 2, 3]
    3. json.dump(data)
    作为标准库,你可以直接import使用,而对于第三方库,你必须先安装,比如http请求库 requests,安装方法也是极为简单,从python3.4开始,pip已经作为python的一部分发布,因此,你不需要额外安装pip,直接使用就好
    1. pip install requests
    就是这么简单,在安装时,你可以指定第三方库的版本
    1. pip install requests==2.22.0
    如果安装成功,一定会出现 Successfully installed 的字样。
    第三方库会经常更新,你可以使用下面的命令罗列出已经过期的第三方库
    1. pip list --outdated
    想要对其中某个库进行升级,可以使用upgrade命令
    1. pip install --upgrade 库名

    2. 在 Python Package Index (PyPI) 上查找第三方库

    人们在实现了一个有着特定功能的第三方库后,会发布到https://pypi.org/ 上,pip在安装过程中会到这个网站上寻找合适的库进行下载和安装,我们自己也可以使用命令进行第三方库查找,需要使用search命令
    1. pip search reqeusts
    使用这个命令可以搜索到非常多的第三方库
    1. requests-hawk (1.0.0) - requests-hawk
    2. requests-dump (0.1.3) - `requests-dump` provides hook functions for requests.
    3. requests-aws4auth (0.9) - AWS4 authentication for Requests
    4. requests-auth (4.0.1) - Easy Authentication for Requests
    5. Requests-OpenTracing (0.2.0) - OpenTracing support for Requests
    6. yamlsettings-requests (1.0.0) - YamlSettings Request Extension
    7. pydantic-requests (0.1.3) - A pydantic integration with requests.
    8. requests-foauth (0.1.1) - Requests TransportAdapter for foauth.org!
    9. requests-core (0.0.0) - A minimal HTTP Client, for Requests.
    10. pyfortified-requests (0.3.6) - Extension to Python `requests` functionality.
    11. requests-file (1.4.3) - File transport adapter for Requests
    我只列了其中一部分,正是因为有了这些延伸到每一个领域里的第三方库,才让python变得无所不能。

    3. 管理requirements.txt文件

    开发一个稍大点的项目,都会用到很多第三方库,在部署这个项目时,项目所在的部署环境也需要安装这些第三方库,那么问题来了,该怎样安装这些第三方库呢,总不能一个一个的使用pip命令来安装吧,就算你有耐心一个一个的安装,你也总应该记录下来,这个项目都使用了哪些第三方库吧,以免安装过程中有遗漏。
    在python项目管理中,会使用requirements.txt文件保存项目所使用的第三方库,其内容类似下面的示例
    1. flask==1.0.2
    2. cacheout==0.11.0
    3. requests==2.19.1
    4. flask-restful==0.3.7
    5. elasticsearch==6.3.1
    6. redis==2.10.5
    7. PyMySQL==0.9.2
    有了这份文件,在部署项目时,安装第三方库就变得方便了
    1. pip install -r requirements.txt
    如果你想检查python第三方库的安装情况,可以使用pip list命令,这个命令会展示出已经安装的第三方库的信息 ```python Package Version

aniso8601 7.0.0 arrow 0.13.0 asn1crypto 0.24.0 bcrypt 3.1.7 bitarray 0.8.3

  1. 如果你想把自己开发环境的所有第三方库信息都保存到requirements.txt文件中,pip同样提供了命令
  2. ```python
  3. pip freeze > requirements.txt

4. 卸载第三方库

卸载第三方库,使用uninstall命令

  1. pip uninstall requests

这时,界面会提示你是否真的卸载,需要你输入y,如果你确实真的想卸载,可以在命令的后面加上-y

  1. pip uninstall requests -y

这样就不会再出现询问的指令了

5. pip支持的全部命令

  1. pip help

使用help 命令,可以查看pip支持的所有命令

  1. Usage:
  2. pip3 <command> [options]
  3. Commands:
  4. install Install packages.
  5. download Download packages.
  6. uninstall Uninstall packages.
  7. freeze Output installed packages in requirements format.
  8. list List installed packages.
  9. show Show information about installed packages.
  10. check Verify installed packages have compatible dependencies.
  11. config Manage local and global configuration.
  12. search Search PyPI for packages.
  13. wheel Build wheels from your requirements.
  14. hash Compute hashes of package archives.
  15. completion A helper command used for command completion.
  16. help Show help for commands.
  17. General Options:
  18. -h, --help Show help.
  19. --isolated Run pip in an isolated mode, ignoring environment variables and user configuration.
  20. -v, --verbose Give more output. Option is additive, and can be used up to 3 times.
  21. -V, --version Show version and exit.
  22. -q, --quiet Give less output. Option is additive, and can be used up to 3 times (corresponding to WARNING, ERROR, and CRITICAL logging levels).
  23. --log <path> Path to a verbose appending log.
  24. --proxy <proxy> Specify a proxy in the form [user:passwd@]proxy.server:port.
  25. --retries <retries> Maximum number of retries each connection should attempt (default 5 times).
  26. --timeout <sec> Set the socket timeout (default 15 seconds).
  27. --exists-action <action> Default action when a path already exists: (s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort).
  28. --trusted-host <hostname> Mark this host as trusted, even though it does not have valid or any HTTPS.
  29. --cert <path> Path to alternate CA bundle.
  30. --client-cert <path> Path to SSL client certificate, a single file containing the private key and the certificate in PEM format.
  31. --cache-dir <dir> Store the cache data in <dir>.
  32. --no-cache-dir Disable the cache.
  33. --disable-pip-version-check
  34. Don't periodically check PyPI to determine whether a new version of pip is available for download. Implied with --no-index.
  35. --no-color Suppress colored output