大家好,我是云计算磊哥,从业20年的IT老鸟。IT架构师培训15年,总结了一套从入门到精通的全运维开发宝典手册。准备用300天时间写一套博文,手把手从安装软件讲起,从linux系统管理,shell脚本编程,mysql运维架构备份核心技术,Apache/nginx/tomcatWEB服务器管理,ansible自动化运维,redis集群哨兵,LVM/HAproxy/keepalived集群架构,rabbitMQ消息队列,docker&K8S集群资源管理,K8S自愈,K8S自动扩容,PYTHON编程基础,PYTHON自动化运维,从行业到产品,从过去到未来,从理论到操作,从视频到文档工具,100+篇系列文章一站式发布。从零基础入门到30k运维开发工程师岗位诸多就业问题。多方位全方面的给你讲清楚云计算这个行业该如何做。关注我。后续AI大模型开发课程更精彩。
十一、模块的导入和使用
1、模块介绍
Python 有时候称为胶水语言,就是因为它有强大的可扩展性,这个扩展性就是用模块实现的。
模块其实就是一个以 .py 结尾的 Python 文件,这个文件中可以包含变量、函数、类等。
模块可以包含实现了一个或者多个功能的代码。
模块可以在其他 Python 文件中使用,可以通过网络进行传播。
这样的话,如果想在你的程序中实现某些功能,其实网络的其他程序猿已经给你写好了,下载下来,安装到自己的环境下,就可以使用了。
2、为什么要模块化
模块化编程是指将大型,笨拙的编程任务分解为单独的,更小的,更易于管理的子任务或模块的过程。然后可以像构建块一样拼凑单个模块以创建更大的应用程序。
在大型应用程序中模块化代码有几个优点:
- **简单性:**模块通常只关注问题的一小部分,而不是关注当前的整个问题。如果您正在处理单个模块,那么您的头脑中要思考的将有一个较小的问题范围。这使得开发更容易,更不容易出错。
- **可维护性:**模块通常设计为能够在不同的问题域之间实施逻辑边界。如果以最小化相互依赖性的方式编写模块,则对单个模块的修改将对程序的其他部分产生影响的可能性降低。(您甚至可以在不了解该模块之外的应用程序的情况下对模块进行更改。)这使得许多程序员团队在大型应用程序上协同工作更加可行。
- **可重用性:**单个模块中定义的功能可以通过应用程序的其他部分轻松地重用。这消除了重新创建重复代码的需要。
- 范围:模块通常定义一个单独的命名空间,这有助于避免程序的不同区域中的变量名之间的冲突。
函数,模块和包都是Python中用于促进代码模块化的构造。
3、模块的分类
1、实现方式分类
实际上有两种不同的方法可以在Python中定义模块:
- 模块可以用C编写并在运行时动态加载,就像
re(正则表达式)模块一样。
以上两种情况下,模块的内容都以相同的方式访问:使用import语句
2、模块的归属分类
- 包含在解释中的一个内置的模块本,像
itertools模块。
3、第三方模块
从网络上下载的模块称为 第三方模块。
安装方法
1、 pip3 工具安装
例如下面的示例是安装用于执行远程主机命令的模块 paramiko
注意: pip3 是 bash 环境下的命令pip3 install paramiko
python2.x 使用 pip python3.x 使用 pip3 当然这也不是固定的,比如你给 pip3 定义了一个别名 pip
2、源码安装
源码安装就是,从网络上下载没有封装的 python 文件的源码,之后在本地执行其源码中的 setup.py 文件进行安装。
模块的源码一般都有一个主目录,主目录中包含了一个到多个子目录和文件。 但是主目录下一定有一个 setup.py 的文件,这个是源码安装的入口文件,就是需要执行这个文件并且传入一个 install 参数进行源码安装。
示例:
a. 下载源码包
wget https://files.pythonhosted.org/packages/4a/1b/9b40393630954b54a4182ca65a9cf80b41803108fcae435ffd6af57af5ae/redis-4.0.1.tar.gz
b. 解压源码包
tar -xf redis-3.0.1.tar.gz
4、自定义模块
有的情况下,是需要自己编写一些模块的,这种就是自定义模块了。
示例:
some_mod.pyx = 10li = ['shark', 18]def foo(): return 30class Person(): def __init__(self, name, age): self.name = name self.age = age
5、内置模块
模块除了 第三方模块, 自定义模块,还有 内置模块。
4、模块的使用
1、导入模块
2、使用模块中的对象
要想使用模块中的变量名或者函数名等,只需要使用 模块名.变量名 的方式即可。
例如,下面是使用的了 some_mod 模块中的 foo 函数。
import some_modsome_mod.foo()
3、更多模块导入的方式
a. 从模块中导入其中的一个对象
b. 从模块中导入多个对象
from some_mod import x, foo
c. 从模块中导入全部的对象, 不建议这么做
4、导入模块时模块的代码会自动被执行一次
st = """www.qfecu.com磊哥欢迎您!www.qfecu.com磊哥欢迎您!"""print(st)
5、模块名的搜索路径
当你导入模块或者包的时候, 查找模块或包的顺序:
- 之后再从
sys.path 输出的值中的路径里查找模块名或者包名。
import sysprint(sys.path)
sys.path 输出的值是一个 Python 的列表,这个列表我们可以对其修改的。
比如我们可以把某个文件的路径添加到此列表中,通常会这么做。
run.pyimport osimport sysBASE_DIR = os.path.dirname(os.path.abspath(__file__)) # python2 sys.path.insert(0, BASE_DIR)sys.path.insert(0,'D:\gitlab') # 将D:\gitlab 添加到python解释器的查询列表中print(sys.path)
十二、常用模块
1、sys 模块
提供了一系列有关Python运行环境的变量和函数
#python3 sys模块#sys模块负责程序与python解释器的交互,提供了一系列的函数和变量,#用于操控python运行时的环境。!# sys.argv 接收命令行参数,生成一个List,第一个元素是程序本身路径# sys.modules.keys() 返回所有已经导入的模块列表# sys.exc_info() 获取当前正在处理的异常类,exc_type、exc_value、exc_traceback当前处理的异常详细信息!# sys.exit(n) 退出程序,正常退出时exit(0)# sys.hexversion 获取Python解释程序的版本值,16进制格式如:0x020403F0# sys.version 获取Python解释程序的版本信息# sys.maxsize 获取内存中最大的Int值 python2中是maxint# sys.maxunicode 获取内存从中最大的Unicode值# sys.modules 返回系统导入的模块字典,key是模块名,value是模块!# sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值!# sys.platform 返回操作系统平台名称# sys.stdout 标准输出# sys.stdin 标准输入# sys.stderr 错误输出!# sys.exec_prefix 返回平台独立的python文件安装的位置# sys.byteorder 本地字节规则的指示器,big-endian平台的值是'big',little-endian平台的值是'little'# sys.copyright 记录python版权相关的东西# sys.api_version 解释器的C的API版本import syssys.argv # 命令行参数列表,第一个元素是程序本身路径;用于接收执行 # Python 脚本时传的参数# 示例:python3 echo.py a b c# echo.py 文件内容import sysprint(sys.argv[1:])# 输出结果['a', 'b', 'c']print('脚本名称:{}'.format(sys.argv[0]))for i in sys.argv: if i == sys.argv[0]: continue print('参数为:',i)print('总参数个数:{}'.format(len(sys.argv)-1)[root@python python]# ./sysargv.py s1 s2 s3 s4 s5脚本名称:./sysargv.py参数为: s1参数为: s2参数为: s3参数为: s4参数为: s5总参数个数:5
2、os 模块
os模块是与操作系统交互的一个接口,包含普遍的操作系统功能,如果你希望你的程序能够与平台有关的话,这个模块是尤为重要的。
import os# os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 # pwd# os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd # cd # os.curdir 返回当前目录: ('.')# os.pardir 获取当前目录的父目录字符串名:('..')# os.makedirs('dirname1/dirname2') 可生成多层递归目录 # mkdir -p# os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推 rmdir -p# os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname # mkdir# os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname # rmdir# os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印 # ls -A# os.remove() 删除一个文件 # rm -f# os.rename("oldname","newname") 重命名文件/目录 rename mv# os.stat('path/filename') 获取文件/目录信息# os.sep 输出操作系统特定的路径分隔符,win下为"\",Linux下为"/"# os.linesep 输出当前平台使用的行终止符,win下为"\r\n",Linux下为"\n"# os.pathsep 输出用于分割文件路径的字符串 win下为;,Linux下为:# os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix'# os.system("bash command") 运行shell命令,直接显示 #一般用于脚本中去打印 # 这种方法实用性不如 os.popen subprocess.getoutput# os.environ 获取系统环境变量# os.path.abspath(path) 返回path规范化的绝对路径# os.path.split(path) 将path分割成目录和文件名二元组返回 # 不去检测文件系统# os.path.dirname(path) 返回path的上一层目录。其实就是os.path.split(path)的第一个元素# os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素# os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False # if [ -e ]# os.path.isabs(path) 如果path是绝对路径,返回True# os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False # if [ -f ]# os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False # if [ -d ]# os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,最后一个绝对路径之前的参数将被忽略# os.path.getatime(path) 返回path所指向的文件或者目录的最后存取时间# os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间开始练习import os# 获取当前工作目录,即当前python脚本工作的目录路径os.getcwd()# 切换当前脚本工作目录;相当于shell下cdos.chdir("./dirname")# 创建单级目录,相当于 shell 中的 mkdir dirnameos.mkdir('dirname')# 递归创建目录os.makedirs('dir1/dir2')# 删除单级空目录,若目录非空则无法删除,并报错。os.rmdir('dirname') # 递归删除 空 目录os.removedirs('dir1/dir2') # 列出指定目录下的所有文件和目录,包括隐藏文件,并以列表方式打印os.listdir('dirname')# 递归查找目录下的文件和目录,返回一个生成器对象。# 生成器对象是个可迭代对象,每一层包含了三个值:# 1. 当前目录路径,2. 其下面的所有子目录, 3. 其下面的所有文件os.walk('dirname')### 练习需求 ###1. 在 /tmp 目录下,创建目录 a/b/c2. 进入到 /tmp/a/b 目录下,创建一个目录 f3. 把当前的工作目录写到 f 目录下的 work.txt 文件内。4. 删除目录 c5. 把 /tmp 目录下及其子目录下的所有文件和目录打印到屏幕上# 如果path存在,返回True;如果path不存在,返回False 在这里值得注意的是,# 在Linux shell 中,Python会认为: / 左边一定是一个目录,而不是文件os.path.exists(path) # 如果path是一个存在的目录,则返回True。否则返回Falseos.path.isdir(path)# 如果path是一个存在的文件,返回True。否则返回Falseos.path.isfile(path)# 删除一个文件os.remove('file')# 重命名文件/目录os.rename("oldname", "new")# 如果path是绝对路径,返回 Trueos.path.isabs(path)# 将 path 分割成目录和文件名二元组返回os.path.split(path)# 返回 文件 或 path 规范化的绝对路径os.path.abspath(path)# 返回path的目录。 其实返回的就是 os.path.split(path) 的第一个元素os.path.dirname(path)# 将多个路径组合后返回,每个路径之间不需要加路径分隔符(\或者/) os.path.join(path1[, path2[, ...]])
3、time 时间模块
1、time 模块
在Python中,通常有这几种方式来表示时间:
# 快速认识它们In [139]: import timeIn [140]: time.time()Out[140]: 1522057206.0065496In [141]: time.localtime() # 本地时间, 结构化时间Out[141]: time.struct_time(tm_year=2026, tm_mon=3, tm_mday=26, tm_hour=17, tm_min=40, tm_sec=53, tm_wday=0, tm_yday=85, tm_isdst=0)In [142]: time.gmtime() # 格林威治时间(UTC)Out[142]: time.struct_time(tm_year=2026, tm_mon=3, tm_mday=26, tm_hour=9, tm_min=43, tm_sec=31, tm_wday=0, tm_yday=85, tm_isdst=0)In [143]: time.strftime("%Y-%m-%d%X")Out[143]: '2026-03-26 17:40:40'#time模块没有time.py文件,是内置到解释器中的模块#三种时间表示方式'''1、时间戳(timestamp): 通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。2、格式化的时间字符串:"2026-09-03 10:02:01"3、元组(struct_time):struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)'''#UTC:(Coordinated Universal Time,世界协调时),亦即格林威治天文时间,世界标准时间。在中国为UTC+8#DST:(Daylight Saving Time),即夏令时。大家开始练习import time#时间戳 time()print(time.time())1535939025.4159343#struct_timelocaltime([secs]) 将一个时间戳转换为当前时区的struct_time。secs参数未提供,则以当前时间为准。#当地时间print(time.localtime(time.time()))time.struct_time(tm_year=2026, tm_mon=9, tm_mday=3, tm_hour=9, tm_min=46, tm_sec=7, tm_wday=0, tm_yday=246, tm_isdst=0)print(time.localtime())time.struct_time(tm_year=2026, tm_mon=9, tm_mday=3, tm_hour=9, tm_min=48, tm_sec=19, tm_wday=0, tm_yday=246, tm_isdst=0)t_local=time.localtime()print(t_local.tm_year)print(t_local.tm_mon)print(t_local.tm_mday)#gmtime([secs]) 将一个时间戳转换为UTC时区(0时区)的struct_time。print(time.gmtime())time.struct_time(tm_year=2026, tm_mon=9, tm_mday=3, tm_hour=1, tm_min=51, tm_sec=38, tm_wday=0, tm_yday=246, tm_isdst=0)mktime(t) : 将一个struct_time转化为时间戳。print(time.mktime(time.localtime()))1535939934.0asctime([t]) : 把一个表示时间struct_time表示为这种形式:'Mon Sep 3 10:01:46 2026'。默认将time.localtime()作为参数传入。print(time.asctime())Mon Sep 3 10:01:46 2026ctime([secs]) : 把一个时间戳转化为time.asctime()的形式,默认time.time()为参数。print(time.ctime())Mon Sep 3 10:05:40 2026strftime(format[, t])# 把一个代表时间的struct_time转化为格式化的时间字符串。# 如果t未指定,将传入time.localtime()。# 如果元组中任何一个元素越界,ValueError的错误将会被抛出。print(time.strftime("%Y-%m-%d%X")) #%X 等同于 %H%M%Sprint(time.strftime("%Y-%m-%d%X",time.localtime()))print(time.strftime("%Y-%m-%d%H:%M:%S"))strptime(string[, format])# 把一个格式化时间字符串转化为struct_time。实际上它是strftime()是逆操作。print(time.strptime('2026-09-03 10:14:53', '%Y-%m-%d %X'))time.struct_time(tm_year=2026, tm_mon=9, tm_mday=3, tm_hour=10, tm_min=14, tm_sec=53, tm_wday=0, tm_yday=246, tm_isdst=-1)sleep(secs)time.sleep(10) #停止10秒,继续运行
格式化时间的变量:
| 格式 | 含义 |
|---|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| 一年中的星期数。(00 - 53星期天是一个星期的开始。)第一个星期天之前的所有天数都放在第0周。 |
| |
| 和%U基本相同,不同的是%W以星期一为一个星期的开始。 |
| |
| |
| |
| |
| |
| |
2、时间的互相转换
In [153]: time.time()Out[153]: 1522071229.4780636In [154]: time.localtime(1522071229.4780636)In [155]: time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(1522071229.4780636))In [156]: time.strptime('2026-03-26 21:41', "%Y-%m-%d %H:%M")In [157]: time.mktime(time.localtime())In [178]: time.ctime(1093849081)Out[178]: 'Mon Aug 30 14:58:01 2004'In [179]: time.asctime(time.localtime())Out[179]: 'Mon Mar 26 21:49:41 2026'In [183]: time.strptime('Mon mar 04 21:53:42 2026')In [182]: time.strptime('Mon mar 04 21:53:42 2026', "%a %b %d %H:%M:%S %Y")time.sleep(5) # 休眠 5 秒钟print(time.clock()) # 精确到毫秒
3、datetime 模块
datetame 是 time 的升级版
import datetimeIn [192]: str(datetime.date.fromtimestamp(time.time()))Out[192]: '2026-03-26'In [193]: str(datetime.datetime.now())Out[193]: '2026-03-26 22:09:44.424473'In [194]: datetime.datetime.now() + datetime.timedelta(3)Out[194]: datetime.datetime(2026, 3, 29, 22, 10, 42, 315584)In [196]: datetime.datetime.now() + datetime.timedelta(minutes=30)Out[196]: datetime.datetime(2026, 3, 26, 22, 41, 32, 44547)In [15]: datetime.date.strftime(datetime.datetime.now(),'%Y-%m')Out[15]: '2026-04'In [16]: datetime.datetime.strftime(datetime.datetime.now(),'%Y-%m')Out[16]: '2026-04'import time,datetimeprint('返回当前时间:',datetime.datetime.now())显示结果:返回当前时间: 2017-12-19 18:13:01.974500print('时间戳直接转成字符串格式: ',datetime.date.fromtimestamp(time.time()))显示结果:时间戳直接转成字符串格式: 2017-12-19print('当前时间精确到微秒:',datetime.datetime.now())显示结果:当前时间精确到微妙: 2017-12-19 18:13:01.974500print('当前时间+3天: ',datetime.datetime.now() + datetime.timedelta(3))显示结果:当前时间+3天: 2017-12-22 18:13:01.974500print('当前时间-3天',datetime.datetime.now() + datetime.timedelta(-3))显示结果:当前时间-3天 2017-12-16 18:13:01.974500print('当前时间+3小时',datetime.datetime.now() + datetime.timedelta(hours=3))显示结果:当前时间+3小时 2017-12-19 21:13:01.974500print('当前时间+30分: ',datetime.datetime.now() + datetime.timedelta(minutes=30))显示结果:当前时间+30分: 2017-12-19 18:43:01.974500print('当前时间+2年:',datetime.datetime.now()+datetime.timedelta(days=365*2))显示结果:当前时间+2年: 2019-12-19 18:13:01.974500c_time = datetime.datetime.now()print('时间替换:', c_time.replace(minute=3,hour=2)) #时间替换显示结果:时间替换: 2017-12-19 02:03:01.974500
4、shutil 压缩打包模块
shutil 是 Python3 中高级的文件 文件夹 压缩包 处理模块
1、拷贝文件
拷贝文件的内容到另一个文件中,参数是文件的相对路径或者绝对路径
import shutil shutil.copyfile('./src.file','./dst.file') #给目标文件命名
2、拷贝文件和权限
import shutilshutil.copy2('f1.log', 'f2.log')
3、递归拷贝
递归的去拷贝文件夹
shutil.copytree(src, dst, symlinks=False, ignore=None)
shutil.copytree('/home','/tmp/hbak', ignore=shutil.ignore_patterns('*.txt'))# 递归拷贝一个文件夹下的所有内容到另一个目录下,目标目录应该是原来系统中不存在的
shutil.ignore_patterns(*patterns) 忽略某些文件
ignore=shutil.ignore_patterns(‘排除的文件名’, ‘排除的文件夹名’) 支持通配符,假如有多个用逗号隔开
4、递归删除
递归删除一个文件夹下的所有内容
shutil.rmtree('/tmp/hb')shutil.rmtree('/tmp/hbad/')# 最后结尾的一定是明确的文件名,不可以类似下面这样shutil.rmtree('/tmp/hbak/*')
5、递归移动
递归的去移动文件,它类似mv命令。
shutil.move('/home/src.file', './shark')
6、压缩
创建压缩包并返回文件路径,例如:zip、tar
# 将 /home/shark 目录下的所以文件打包压缩到当前目录下,# 名字 shark,格式 gztar。扩展名会自动根据格式自动生成。shutil.make_archive('shark', # 压缩后文件名 'gztar', # 指定的压缩格式 '/home/shark/') # 被压缩的文件夹名字# 将 /home/shark 目录下的所以文件打包压缩到 /tmp 目录下,名字shark,格式 tarshutil.make_archive( '/tmp/shark','tar','/home/shark/')# 查看当前 python 环境下支持的压缩格式ret = shutil.get_archive_formats()print(ret)
7、解压缩
# 解压的文件名 解压到哪个路径下,压缩的格式shutil.unpack_archive('./a/b.tar.gz', './a/c/','gztar')
5、subprocess 模块执行本机系统命令
os.system() 执行的命令只是把命令的结果输出导终端,程序中无法拿到执行命令的结果。
subprocess 是开启一个系统底层的单个进程,执行 shell 命令,可以得到命令的执行结果。
# 在 shell 中运行命令,并且获取到标准正确输出、标准错误输出In [209]: subprocess.getoutput('ls |grep t')Out[209]: 'test.py' In [222]: ret = subprocess.getstatusoutput('date -u')In [223]: retOut[223]: (0, '2026年 03月 26日 星期一 14:46:42 UTC')
6、Python3 正则模块(标准库)
1、常用特殊字符匹配内容
字符匹配:
| |
|---|
| |
| |
| |
| |
| |
| |
re.S(re.DOTALL) 使 . 匹配包括换行在内的所有字符re.U(re.UNICODE) 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.re.X(re.VERBOSE) 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 | |
In [26]: stringOut[26]: 'isinstance yangge enumerate www.qfedu.com 1997'In [27]: r = re.split("a", string, 1)
使用多个界定符分割字符串
>>> line = 'asdf fjdk; afed, fjek,asdf, foo'>>> import re>>> re.split(r'[;,\s]\s*', line)['asdf', 'fjdk', 'afed', 'fjek', 'asdf', 'foo']
3、正则分组
从已经成功匹配的内容中,再去把想要的取出来
# matchIn [64]: stringOut[64]: 'isinstance yangge enumerate www.qfedu.com 1997'In [65]: r = re.match("is(\w+)", string)In [66]: r.group()Out[66]: 'isinstance'In [67]: r.groups()Out[67]: ('instance',)In [68]: r = re.match("is(in)(\w+)", string))In [69]: r.groups()Out[69]: ('in', 'stance')# search# 命名分组In [87]: r = re.search("is\w+\s(?P<name>y\w+e)", string) In [88]: r.group()Out[88]: 'isinstance yangge'In [89]: r.groups()Out[89]: ('yangge',)6In [90]: r.groupdict()Out[90]: {'name': 'yangge'}8# findallIn [98]: stringOut[98]: 'isinstance all yangge any enumerate www.qfedu.com 1997'In [99]: r = re.findall("a(?P<name>\w+)", string)In [100]: rOut[100]: ['nce', 'll', 'ngge', 'ny', 'te']In [101]: r = re.findall("a(\w+)", string)In [102]: rOut[102]: ['nce', 'll', 'ngge', 'ny', 'te']# splitIn [113]: stringOut[113]: 'isinstance all yangge any enumerate www.qfedu.com 1997'In [114]: r = re.split("(any)", string)In [115]: rOut[115]: ['isinstance all yangge ', 'any', ' enumerate www.qfedu.com 1997']In [116]: r = re.split("(a(ny))", string)In [117]: rOut[117]:['isinstance all yangge ', 'any', 'ny', ' enumerate www.qfedu.com 1997']In [118]: tag = 'value="1997/07/01"'In [119]: s = re.sub(r'(value="\d{4})/(\d{2})/(\d{2}")', r'\1-\2-\3', tag)In [120]: sOut [120]: value="1997-07-01"
对于程序频繁使用的表达式,编译这些表达式会更有效。
compile 函数用于编译正则表达式,返回的是一个正则表达式( Pattern )对象,利用这个对象的相关方法再去匹配字符串。
好处:
re 模块会维护已编译表达式的一个缓存。
不过,这个缓存的大小是有限的,直接使用已编译的表达式可以避免缓存查找开销。
使用已编译表达式的另一个好处是,通过在加载模块时预编译所有表达式,可以把编译工作转到应用 一开始时,而不是当程序响应一个用户动作时才进行编译。
In [130]: regexes = re.compile("y\w+")In [131]: r = regexes.search(string)In [132]: r.group()Out[132]: 'yangge'
# IP:r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b"# 手机号:r'\b1[3|4|5|6|7|8|9][0-9]\d{8}'# 邮箱:shark123@qq.comshark123@163.comr'[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+'
# 匹配所有包含小数在内的数字print(re.findall('\d+\.?\d*',"asdfasdf123as1.13dfa12adsf1asdf3")) #['123', '1.13', '12', '1', '3']#.*默认为贪婪匹配print(re.findall('a.*b','a1b22222222b')) #['a1b22222222b']#.*?为非贪婪匹配:推荐使用print(re.findall('a.*?b','a1b22222222b')) #['a1b']
# \b 表示匹配单词边界,详见后面的速查表In [17]: re.search('hello\b', 'hello world')In [18]: re.search('hello\\b', 'hello world')Out[18]: <_sre.SRE_Match object; span=(0, 5), match='hello'>
Python 自己也有转义
使用 r 禁止 Python 转义
In [19]: re.search(r'hello\b', 'hello world')Out[19]: <_sre.SRE_Match object; span=(0, 5), match='hello'>
最后一个参数 flag
可选值有:
示例:
In [186]: s1 = string.capitalize()In [187]: s1Out[187]: 'Isinstance all yangge any enumerate www.qfedu.com 1997'In [192]: r = re.search('is',s, re.I)Out[192]: <_sre.SRE_Matchobject; span=(0,2), match='Is'>
4、正则模式速查表
| |
|---|
| |
| |
| 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。 |
| 用来表示一组字符,单独列出:[amk] 匹配 ‘a’,‘m’或’k’ |
| 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。 |
| |
| |
| 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式 |
| 匹配n个前面表达式。。例如,"o{2}“不能匹配"Bob"中的"o”,但是能匹配"food"中的两个o。 |
| 精确匹配n个前面表达式。例如,"o{2,}“不能匹配"Bob"中的"o”,但能匹配"foooood"中的所有o。"o{1,}“等价于"o+”。"o{0,}“则等价于"o*”。 |
| 匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式 |
| |
| |
| 正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。 |
| 正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。 |
| |
| |
| |
| |
| 前向肯定界定符。如果所含正则表达式,以 … 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。 |
| 前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功 |
| |
| |
| |
| |
| |
| |
| |
| |
| 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。 |
| |
| |
| 匹配一个单词边界,也就是指单词和空格间的位置。例如, ‘er\b’ 可以匹配"never" 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’。 |
| 匹配非单词边界。‘er\B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’。 |
| |
| |
| 匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。 |
7、Python3 邮件模块
使用第三方库 yagmail
更新: 第三种方式的隐藏用户名和密码的方式,目前不再支持
1、简单介绍 yagmail
目标是尽可能简单,无痛地发送电子邮件。
最终的代码如下:
import yagmailyag = yagmail.SMTP()contents = ['This is the body, and here is just text http://somedomain/image.png', 'You can find an audio file attached.', '/local/path/song.mp3']yag.send('to@someone.com', '邮件标题', contents)
或者在一行中实现:
yagmail.SMTP('mygmailusername').send('to@someone.com', 'subject', 'This is the body')
当然, 以上操作需要从你自己系统的密钥环中读取你的邮箱账户和对应的密码。关于密钥环稍后会提到如何实现。
2、安装模块
pip3 install yagmail # linux / Macpip install yagmail # windows
这样会安装最新的版本,并且会支持所有最新功能,主要是支持从密钥环中获取到邮箱的账户和密码。
3、关于账户和密码
开通自己邮箱的 SMTP 功能,并获取到授权码
这个账户是你要使用此邮箱发送邮件的账户,密码不是平时登录邮箱的密码,而是开通 POP3/SMTP 功能后设置的客户端授权密码。
这里以 126 邮箱为例:
1.登录邮箱
2.顶部菜单 设置
3.设置中选择 pop3
4.勾选POP3详情页所有的选项(POP3服务,IMAP服务,开启提醒),保存
5.找到客户端授权码,并启用
4、方式一:不使用系统的密钥环
不使用系统的密钥环,可以直接暴露账户和密码在脚本里
import yagmailyag = yagmail.SMTP( user='自己的账号', password='账号的授权码', host='smtp.qq.com', # 邮局的 smtp 地址 port='端口号', # 邮局的 smtp 端口 smtp_ssl=False)yag.send(to='收件箱账号', subject='邮件主题', contents='邮件内容')
5、方式二: 使用系统的密钥环管理账户和授权码
模块支持从当前系统环境中的密钥环中获取账户和密码,要想实现这个功能,需要依赖模块 keyring。之后把账户和密码注册到系统的密钥环中即可实现。
1. 安装依赖模块
pip3 install keyring # CentOS7.3 还需要安装下面的模块pip3 install keyrings.alt
2. 开始向密钥环注册
import yagmailyagmail.register('你的账号', '你的授权密码')
注册账户和密码,只需要执行一次即可。
3. 发送邮件
import yagmailyag = yagmail.SMTP('自己的账号', host='smtp.qq.com', # 邮局的 smtp 地址 port='端口号', # 邮局的 smtp 端口 smtp_ssl=False # 不使用加密传输)yag.send( to='收件箱账号', subject='邮件主题', contents='邮件内容')
6、示例展示
下面是以我的 126 邮箱为例, 使用系统密钥环的方式,向我的 163邮箱发送了一封邮件。
import yagmailyag = yagmail.SMTP(user='shark@126.com', host='smtp.126.com', port=25, smtp_ssl=False)yag.send(to='docker@163.com', subject='from shark', contents='test')
这样就愉快的发送了一封测试邮件到 docker@163.com 的邮箱。
当然前提是:
- 把 126 邮箱的账号和密码已经注册到自己系统的密钥环中。
7、发送附件
发送
发送附件只需要给 send方法传递 attachments 关键字参数
比如我在系统的某一个目录下有一张图片,需要发送给 docker@163.com
import yagmailyag = yagmail.SMTP(user='shark@126.com', host='smtp.126.com', port=25, smtp_ssl=False)yag.send(to='docker@163.com', subject='from shark', contents='test', attachments='./松鼠.jpeg')
8、收到的邮件和附件
登录邮箱查看邮件
9、使用 ssl 发送加密邮件
要发送加密邮件,只需要把 smtp_ssl 关键字参数去掉即可,因为默认就是采用的加密方式 smtp_ssl=True。
不传递 stmp_ssl 关键字参数的同时,需要设置端口为邮箱服务提供商的加密端口,这里还是以 126 邮箱为例,端口是 465。
import yagmailyag = yagmail.SMTP(user='shark@126.com', host='smtp.126.com', port=465)yag.send(to='docker@163.com', subject='from sharkyunops', contents='test', attachments='./松鼠.jpeg')
10、发送 带 html 标记语言的邮件内容
在实际的生产环境中,经常会发送邮件沟通相关事宜,往往会有表格之类的内容,但是又不想以附件的形式发送,就可以利用 html 标记语言的方式组织数据。
import yagmailyag = yagmail.SMTP(user='shark@126.com', host='smtp.126.com', port=465)html="""<tableborder="1"> <thead> <tr> <th>姓名</th> <th>年龄</th> </tr> </thead> <tbody> <tr> <td>shak</td> <td>18</td> </tr> <tr> <td>西瓜甜</td> <td>28</td> </tr> </tbody></table>"""yag.send(to='docker@163.com', subject='from sharkyunops', contents=['test',html])
登录邮箱接收邮件
11、更多
如果不指定to参数,则发送给自己
如果to参数是一个列表,则将该邮件发送给列表中的所有用户
attachments 参数的值可以是列表,表示发送多个附件
8、Python3 paramiko 模块
Paramiko 模块提供了基于ssh连接,进行远程登录服务器执行命令和上传下载文件的功能。这是一个第三方的软件包,使用之前需要安装。
1、安装
2、执行命令
1、基于用户名和密码的连接
封装 Transport
import paramiko #实例化一个transport(传输)对象transport = paramiko.Transport(('172.16.32.129',2323))#建立连接transport.connect(username='root',password='123')#建立ssh对象ssh = paramiko.SSHClient()#绑定transport到ssh对象ssh._transport=transport#执行命令stdin,stdout,stderr=ssh.exec_command('df')#打印输出print(stdout.read().decode())#关闭连接transport.close()import paramikotransport = paramiko.Transport(('172.16.153.134', 22))transport.connect(username='root', password='upsa')ssh = paramiko.SSHClient()ssh._transport = transportstdin, stdout, stderr = ssh.exec_command('df -P')print(stdout.read().decode())transport.close()
3、文件上传下载
SFTPClient:
用于连接远程服务器并进行上传下载功能。
下面的命令可以快速创建密钥对,并用 -t 指定了算法类型为 ecdsa
ssh-keygen -t ecdsa -N “” ssh-keygen ssh-copy-id 192.168.95.154
1、基于用户名密码上传下载
import paramikotransport = paramiko.Transport(('10.18.46.104',22))transport.connect(username='root',password='123.com')#paramiko.SSHClient()sftp = paramiko.SFTPClient.from_transport(transport)# 将ssh-key.py 上传至服务器 /tmp/ssh-key.pysftp.put('ssh-key.py', '/tmp/ssh-key.txt') # 后面指定文件名称# 将远程主机的文件 /tmp/ssh-key.py 下载到本地并命名为 ssh-key.txtsftp.get('/tmp/ssh-key.py', 'ssh-key.txt')transport.close()