欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

python的常用模块

程序员文章站 2022-07-10 08:23:07
...

一、 时间模块time() 与 datetime()

1. time()模块中的重要函数
函数 描述
asctime([tuple]) 将时间元组转换为字符串
localtime([secs]) 将秒数转换为日期元组(转换成本国时区而不是utc时区)
mktime(tuple) 将时间元组转换为本地时间
sleep(secs) 休眠(不做任何事情)secs秒
strptime(string[, format]) 将字符串解析为时间元组
time() 获取当前时间戳
time.gmtime() 将时间转换成utc格式的元组格式

2 、time()模块时间转换

  1. 时间戳 1970年1月1日之后的秒, 即:time.time()
  2. 格式化的字符串 2014-11-11 11:11, 即:time.strftime(’%Y-%m-%d’)
  3. 结构化时间 元组包含了:年、日、星期等… time.struct_time 即:time.localtime()
import time
print(time.time())                              # 时间戳:1511166937.2178104
print(time.strftime('%Y-%m-%d'))                 # 格式化的字符串: 2017-11-20
print(time.localtime())                         # 结构化时间(元组): (tm_year=2017, tm_mon=11...)
print(time.gmtime())                            # 将时间转换成utc格式的元组格式: (tm_year=2017, tm_mon=11...)

#1. 将结构化时间转换成时间戳: 1511167004.0
print(time.mktime(time.localtime()))

#2. 将格字符串时间转换成结构化时间 元组: (tm_year=2017, tm_mon=11...)
print(time.strptime('2014-11-11', '%Y-%m-%d'))

#3. 结构化时间(元组) 转换成  字符串时间  :2017-11-20
print(time.strftime('%Y-%m-%d', time.localtime()))  # 默认当前时间

#4. 将结构化时间(元组) 转换成英文字符串时间 : Mon Nov 20 16:51:28 2017
print(time.asctime(time.localtime()))

#5. 将时间戳转成 英文字符串时间 : Mon Nov 20 16:51:28 2017
print(time.ctime(time.time()))

4、ctime和asctime区别

​    1)ctime传入的是以秒计时的时间戳转换成格式化时间

​   2)asctime传入的是时间元组转换成格式化时间

import time
t1 = time.time()
print(t1)               #1483495728.4734166
print(time.ctime(t1))   #Wed Jan  4 10:08:48 2017
t2 = time.localtime()
print(t2)      #time.struct_time(tm_year=2017, tm_mon=1, tm_mday=4, tm_hour=10, print(time.asctime(t2)) #Wed Jan  4 10:08:48 2017 

5、datetime

获取时间

import datetime
#1、datetime.datetime获取当前时间
print(datetime.datetime.now())
#2、获取三天后的时间
print(datetime.datetime.now()+datetime.timedelta(+3))
#3、获取三天前的时间
print(datetime.datetime.now()+datetime.timedelta(-3))
#4、获取三个小时后的时间
print(datetime.datetime.now()+datetime.timedelta(hours=3))
#5、获取三分钟以前的时间
print(datetime.datetime.now()+datetime.timedelta(minutes = -3))

import datetime
print(datetime.datetime.now())                                   #2017-08-18 11:25:52.618873
print(datetime.datetime.now().date())                            #2017-08-18
print(datetime.datetime.now().strftime("%Y-%m-%d %H-%M-%S"))    #2017-08-18 11-25-52

时间转换

#1、datetime对象与str转化
# datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
'2018-03-09 10:08:50'

# datetime.datetime.strptime('2016-02-22',"%Y-%m-%d")
datetime.datetime(2016, 2, 22, 0, 0)

#2、datetime对象转时间元组
# datetime.datetime.now().timetuple()
time.struct_time(tm_year=2018, tm_mon=3, tm_mday=9,

#3、时间戳转换成datetime对象
# datetime.datetime.fromtimestamp(1520561646.8906238)
datetime.datetime(2018, 3, 9, 10, 14, 6, 890624)

6、本地时间与utc时间相互转换

import time
import datetime

def utc2local(utc_st):
    ''' 作用:将UTC时间装换成本地时间
    :param utc_st: 传入的是utc时间(datatime对象)
    :return:  返回的是本地时间 datetime 对象
    '''
    now_stamp = time.time()
    local_time = datetime.datetime.fromtimestamp(now_stamp)
    utc_time = datetime.datetime.utcfromtimestamp(now_stamp)
    offset = local_time - utc_time
    local_st = utc_st + offset
    return local_st

def local2utc(local_st):
    ''' 作用:将本地时间转换成UTC时间
    :param local_st: 传入的是本地时间(datatime对象)
    :return: 返回的是utc时间 datetime 对象
    '''
    time_struct = time.mktime(local_st.timetuple())
    utc_st = datetime.datetime.utcfromtimestamp(time_struct)
    return utc_st

utc_time = datetime.datetime.utcfromtimestamp(time.time())
# utc_time = datetime.datetime(2018, 5, 6, 5, 57, 9, 511870)        # 比北京时间晚了8个小时
local_time = datetime.datetime.now()
# local_time = datetime.datetime(2018, 5, 6, 13, 59, 27, 120771)    # 北京本地时间

utc_to_local = utc2local(utc_time)
local_to_utc = local2utc(local_time)
print utc_to_local       # 2018-05-06 14:02:30.650270     已经转换成了北京本地时间
print local_to_utc       # 2018-05-06 06:02:30            转换成北京当地时间

django的timezone时间与本地时间转换

from django.utils import timezone
from datetime import datetime

utc_time = timezone.now()
local_time = datetime.now()

#1、utc时间装换成本地时间
utc_to_local = timezone.localtime(timezone.now())

#2、本地时间装utc时间
local_to_utc = timezone.make_aware(datetime.now(), timezone.get_current_timezone())
**7、Python计算两个日期之间天数**
import datetime
d1 = datetime.datetime(2018,10,31)   # 第一个日期
d2 = datetime.datetime(2019,2,2)     # 第二个日期
interval = d2 - d1                   # 两日期差距
print(interval.days)                 # 具体的天数

二、random()模块

1、random()模块常用函数

函数 描述
random() 返回0<n<=1
getrandbits(n) 以长整形形式返回n个随机位
uniform(a, b) 返回随机实数n,其中a<=n<=b
randrange([start], stop, [step]) 返回range(start,stop,step)中的随机数
choice(seq) 从序列seq中返回随意元素
shuffle(seq[, random]) 原地指定序列seq(将有序列表变成无序的:洗牌)
sample(sea, n) 从序列seq中选择n个随机且独立的元素

2、random常用函数举例

import random
#⒈ 随机整数:
print(random.randint(0,99))             # 随机选取0-99之间的整数
print(random.randrange(0, 101, 2))      # 随机选取0-101之间的偶数

#⒉ 随机浮点数:
print(random.random())                   # 0.972654134347
print(random.uniform(1, 10))             # 4.14709813772

#⒊ 随机字符:
print(random.choice('abcdefg'))         # c
print(random.sample('abcdefghij',3))    # ['j', 'f', 'c']

3、使用random实现四位验证码

使用for循环实现

import random
checkcode = ''
for i in range(4):
    current = random.randrange(0,4)
    if current == i:
        tmp = chr(random.randint(65,90))    #65,90表示所有大写字母
    else:
        tmp = random.randint(0,9)
    checkcode += str(tmp)
print(checkcode)                            #运行结果: 851K

使用random.sample实现

import random
import string
str_source = string.ascii_letters + string.digits
str_list = random.sample(str_source,7)

#['i', 'Q', 'U', 'u', 'A', '0', '9']
print(str_list)
str_final = ''.join(str_list)

#iQUuA09
print(str_final)            # 运行结果: jkFU2Ed
>>> import string
>>> string.digits
'0123456789'
>>> string.ascii_lowercase
'abcdefghijklmnopqrstuvwxyz'

三、os模块

os模块常用方法

import os
#1 当前工作目录,即当前python脚本工作的目录路径
print(os.getcwd())    # C:\Users\admin\PycharmProjects\s14\Day5\test4

#2 当前脚本工作目录;相当于shell下cd
os.chdir("C:\\Users\\admin\\PycharmProjects\\s14")
os.chdir(r"C:\Users\admin\PycharmProjects\s14")
print(os.getcwd())    # C:\Users\admin\PycharmProjects\s14

#3 返回当前目录: ('.')
print(os.curdir)        # ('.')

#4 获取当前目录的父目录字符串名:('..')
print(os.pardir)        # ('..')

#5 可生成多层递归目录
os.makedirs(r'C:\aaa\bbb')         # 可以发现在C盘创建了文件夹/aaa/bbb

#6 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.removedirs(r'C:\aaa\bbb')    # 删除所有空目录

#7 生成单级目录;相当于shell中mkdir dirname
os.mkdir(r'C:\bbb')        # 仅能创建单个目录

#8 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.rmdir(r'C:\aaa')        # 仅删除指定的一个空目录

#9 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
print(os.listdir(r"C:\Users\admin\PycharmProjects\s14"))

#10 删除一个文件
os.remove(r'C:\bbb\test.txt')        # 指定删除test.txt文件

#11 重命名文件/目录
os.rename(r'C:\bbb\test.txt',r'C:\bbb\test00.bak')

#12 获取文件/目录信息
print(os.stat(r'C:\bbb\test.txt'))

#13 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
print(os.sep)                # \

#14 输出当前平台使用的行终止符,win下为"\r\n",Linux下为"\n"
print(os.linesep)

#15 输出用于分割文件路径的字符串
print(os.pathsep)                # ;  (分号)

#16 输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
print(os.name)                # nt

#17 运行shell命令,直接显示
os.system("bash command")

#18 获取系统环境变量
print(os.environ)                # environ({'OS': 'Windows_NT', 'PUBLIC': ………….

#19 返回path规范化的绝对路径
print(os.path.abspath(r'C:/bbb/test.txt'))    # C:\bbb\test.txt

#20 将path分割成目录和文件名二元组返回
print(os.path.split(r'C:/bbb/ccc'))    # ('C:/bbb', 'ccc')

#21 返回path的目录。其实就是os.path.split(path)的第一个元素
print(os.path.dirname(r'C:/bbb/ccc'))    # C:/bbb

#22 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
print(os.path.basename(r'C:/bbb/ccc/ddd'))    # ddd

#23 如果path存在,返回True;如果path不存在,返回False
print(os.path.exists(r'C:/bbb/ccc/'))    # True

#24 如果path是绝对路径,返回True        # True
print(os.path.isabs(r"C:\Users\admin\PycharmProjects\s14\Day5\test4"))

#25 如果path是一个存在的文件,返回True。否则返回False
print(os.path.isfile(r'C:/bbb/ccc/test2.txt'))        # True

#26 如果path是一个存在的目录,则返回True。否则返回False
print(os.path.isdir(r'C:/bbb/ccc'))            # True

#28 返回path所指向的文件或者目录的最后存取时间
print(os.path.getatime(r'C:/bbb/ccc/test2.txt'))        # 1483509254.9647143

#29 返回path所指向的文件或者目录的最后修改时间
print(os.path.getmtime(r'C:/bbb/ccc/test2.txt'))        # 1483510068.746478

#30 无论linux还是windows,拼接出文件路径
put_filename = '%s%s%s'%(self.home,os. path.sep, filename)
#C:\Users\admin\PycharmProjects\s14\day10select版FTP\home

os命令创建文件夹: C:/aaa/bbb/ccc/ddd并写入文件file1.txt

import os

os.makedirs('C:/aaa/bbb/ccc/ddd',exist_ok=True)       # exist_ok=True:如果存在当前文件夹不报错
path = os.path.join('C:/aaa/bbb/ccc','ddd',)
f_path = os.path.join(path,'file.txt')

with open(f_path,'w',encoding='utf8') as f:
    f.write('are you ok!!')

将其他目录的绝对路径动态的添加到pyhton的环境变量中

import os,sys
print(os.path.dirname( os.path.dirname( os.path.abspath(__file__) ) ))
BASE_DIR = os.path.dirname( os.path.dirname( os.path.abspath(__file__) ) )
sys.path.append(BASE_DIR)

# 代码解释:
# 要想导入其他目录中的函数,其实就是将其他目录的绝对路径动态的添加到pyhton的环境变量中,这样python解释器就能够在运行时找到导入的模块而不报错:
# 然后调用sys模块sys.path.append(BASE_DIR)就可以将这条路径添加到python环境变量中

1、os.popen获取脚本执行结果

data.py

data = {'name':'aaa'}
import json
print json.dumps(data)

get_data.py

import os,json

ret = os.popen('python data.py')
data = ret.read().strip()
ret.close()
data = json.loads(data)
print data  # {'name':'aaa'}

四、sys模块

1、 sys基本方法

方法 描述
sys.argv 返回执行脚本传入的参数
sys.exit(n) 退出程序,正常退出时exit(0)
sys.version 获取Python解释程序的版本信息
sys.maxint 最大的Int值
sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform 返回操作系统平台名称
sys.stdout.write(‘please:’)
val = sys.stdin.readline()[:-1]

2、使用sys返回运行脚本参数

sys.argv返回执行脚本传入的参数

import sys
# C:\Users\tom\PycharmProjects\s14Review\day01>  python test01.py 1 2 3
print(sys.argv)         # 打印所有参数                 ['test01.py', '1', '2', '3']
print(sys.argv[1:])     # 获取索引 1 往后的所有参数     ['1', '2', '3']

五、tarfile用于将文件夹归档成 .tar的文件

tarfile使用

import tarfile
# 将文件夹Day1和Day2归档成your.rar并且在归档文件夹中Day1和Day2分别变成bbs2.zip和ccdb.zip的压缩文件
tar = tarfile.open('your.tar','w')
tar.add(r'C:\Users\admin\PycharmProjects\s14\Day1', arcname='bbs2.zip')
tar.add(r'C:\Users\admin\PycharmProjects\s14\Day2', arcname='cmdb.zip')
tar.close()

# 将刚刚的归档文件your.tar进行解压解压的内容是bbs2.zip和cmdb.zip压缩文件而不是变成原有的文件夹
tar = tarfile.open('your.tar','r')
tar.extractall()  # 可设置解压地址
tar.close()

六、shutil 创建压缩包,复制,移动文件

注 : shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的
  作用: shutil 创建压缩包并返回文件路径(如:zip、tar),并且可以复制文件,移动文件

shutil使用

import shutil
#1 copyfileobj()  将文件test11.txt中的内容复制到test22.txt文件中
f1 = open("test11.txt",encoding="utf-8")
f2 = open("test22.txt",'w',encoding="utf-8")
shutil.copyfileobj(f1,f2)

#2  copyfile()  直接指定文件名就可进行复制
shutil.copyfile("test11.txt",'test33.txt')

#3  shutil.copymode(src, dst) 仅拷贝权限。内容、组、用户均不变

#4  shutil.copystat(src, dst)  拷贝状态的信息,包括:mode bits, atime, mtime, flags
shutil.copystat('test11.txt','test44.txt')

#5  递归的去拷贝目录中的所有目录和文件,这里的test_dir是一个文件夹,包含多级文件夹和文件
shutil.copytree("test_dir","new_test_dir")

#6  递归的去删除目录中的所有目录和文件,这里的test_dir是一个文件夹,包含多级文件夹和文件
shutil.rmtree("test_dir")

#7 shutil.move(src, dst)  递归的去移动文件
shutil.move('os_test.py',r'C:\\')

#8  shutil.make_archive(base_name, format,...) 创建压缩包并返回文件路径,例如:zip、tar
'''
   1. base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
        如:www                        =>保存至当前路径
        如:/Users/wupeiqi/www =>保存至/Users/wupeiqi/
   2.  format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
   3. root_dir: 要压缩的文件夹路径(默认当前目录)
   4. owner: 用户,默认当前用户
   5. group: 组,默认当前组
   6. logger: 用于记录日志,通常是logging.Logger对象

'''
#将C:\Users\admin\PycharmProjects\s14\Day4 的文件夹压缩成 testaa.zip
shutil.make_archive("testaa","zip",r"C:\Users\admin\PycharmProjects\s14\Day4")

七、zipfile将文件或文件夹进行压缩

zipfile使用

import zipfile
#将文件main.py和test11.py压缩成day5.zip的压缩文件
z = zipfile.ZipFile('day5.zip', 'w')
z.write('main.py')
z.write("test11.txt")
z.close()

#将刚刚压缩的day5.zip文件进行解压成原文件
z = zipfile.ZipFile('day5.zip', 'r')
z.extractall()
z.close()

八、shelve 模块

**作用:**shelve模块是一个简单的k,v将内存数据通过文件持久化的模块,可以持久化任何pickle可支持的python数据格式

shelve持久化

import shelve
import datetime
#1 首先使用shelve将.py中定义的字典列表等读取到指定文件shelve_test中,其实我们可不必关心在文件中是怎样存储的
d = shelve.open('shelve_test')   #打开一个文件
info = {"age":22,"job":"it"}
name = ["alex","rain","test"]
d["name"] = name                  #持久化列表
d["info"] = info
d["date"] = datetime.datetime.now()
d.close()

#2 在这里我们可以将刚刚读取到 shelve_test文件中的内容从新获取出来
d = shelve.open('shelve_test')   # 打开一个文件
print(d.get("name"))             # ['alex', 'rain', 'test']
print(d.get("info"))             # {'job': 'it', 'age': 22}
print(d.get("date"))             # 2017-11-20 17:54:21.223410

九、json和pickle序列化

1、json序列化

1. 序列化 (json.dumps) :是将内存中的对象存储到硬盘,变成字符串

2. 反序列化(json.loads) : 将刚刚保存在硬盘中的内存对象从新加载到内存中

json.dumps( data,ensure_ascii=False, indent=4)

json序列化

#json序列化代码
import json
info = {
    'name':"tom",
    "age" :"100"
}
f = open("test.txt",'w')
# print(json.dumps(info))
f.write(json.dumps(info))
f.close()

json反序列化

#json反序列化代码
import json
f = open("test.txt","r")
data = json.loads(f.read())
f.close()
print(data["age"])

2、pickle序列化

  1. python的pickle模块实现了python的所有数据序列和反序列化。基本上功能使用和JSON模块没有太大区别,方法也同样是dumps/dump和loads/load
  2. 与JSON不同的是pickle不是用于多种语言间的数据传输,它仅作为python对象的持久化或者python程序间进行互相传输对象的方法,因此它支持了python所有的数据类型。

pickle序列化

#pickle序列化代码
import pickle
info = {
    'name':"tom",
    "age" :"100"
}
f = open("test.txt",'wb')
f.write(pickle.dumps(info))
f.close()

pickle反序列化

#pickle反序列化代码
import pickle
f = open("test.txt","rb")
data = pickle.loads(f.read())
f.close()
print(data["age"])

3、解决JSON不可以序列化datetime类型

import json,datetime

class JsonCustomEncoder(json.JSONEncoder):
    def default(self, field):
        if isinstance(field, datetime.datetime):
            return field.strftime('%Y-%m-%d %H:%M:%S')
        elif isinstance(field, datetime.date):
            return field.strftime('%Y-%m-%d')
        else:
            return json.JSONEncoder.default(self, field)

t = datetime.datetime.now()

print(type(t),t)
f = open('ttt','w')                              #指定将内容写入到ttt文件中
f.write(json.dumps(t,cls=JsonCustomEncoder))      #使用时候只要在json.dumps增加个cls参数即可

4、JSON和pickle模块的区别

  1. JSON只能处理基本数据类型。pickle能处理所有Python的数据类型。
  2. JSON用于各种语言之间的字符转换。pickle用于Python程序对象的持久化或者Python程序间对象网络传输,但不同版本的Python序列化可能还有差异

十、hashlib 模块

1、用于加密相关的操作,代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法

五种简单加密方式

import hashlib

#1 ######## md5 ########
# 目的:实现对b"HelloIt's me" 这句话进行md5加密
m = hashlib.md5()            # 1)生成一个md5加密对象
m.update(b"Hello")          # 2)使用m对 b"Hello" 加密
m.update(b"It's me")        # 3) 使用m对 b"It's me"加密
print(m.hexdigest())         # 4) 最终加密结果就是对b"HelloIt's me"加密的md5值:5ddeb47b2f925ad0bf249c52e342728a

#2 ######## sha1 ########
hash = hashlib.sha1()
hash.update(b'admin')
print(hash.hexdigest())

#3 ######## sha256 ########
hash = hashlib.sha256()
hash.update(b'admin')
print(hash.hexdigest())

#4 ######## sha384 ########
hash = hashlib.sha384()
hash.update(b'admin')
print(hash.hexdigest())

#5 ######## sha512 ########
hash = hashlib.sha512()
hash.update(b'admin')
print(hash.hexdigest())

2、以上加密算法虽然依然非常厉害,但时候存在缺陷,即:通过撞库可以反解。所以,有必要对加密算法中添加自定义key再来做加密。

hmac添加自定义key加密

######### hmac ########
import hmac
h = hmac.new(b"123456","真实要传的内容".encode(encoding="utf-8"))
print(h.digest())
print(h.hexdigest())
# 注:hmac是一种双重加密方法,前面是加密的内容,后面才是真实要传的数据信息

十一、subprocess 模块

1、subprocess原理以及常用的封装函数

  1. 运行python的时候,我们都是在创建并运行一个进程。像Linux进程那样,一个进程可以fork一个子进程,并让这个子进程exec另外一个程序
  2. 在Python中,我们通过标准库中的subprocess包来fork一个子进程,并运行一个外部的程序。
  3. subprocess包中定义有数个创建子进程的函数,这些函数分别以不同的方式创建子进程,所以我们可以根据需要来从中选取一个使用
  4. 另外subprocess还提供了一些管理标准流(standard stream)和管道(pipe)的工具,从而在进程间使用文本通信。

subprocess常用函数

#1、返回执行状态:0 执行成功
retcode = subprocess.call(['ping', 'www.baidu.com', '-c5'])

#2、返回执行状态:0 执行成功,否则抛异常
subprocess.check_call(["ls", "-l"])

#3、执行结果为元组:第1个元素是执行状态,第2个是命令结果
>>> ret = subprocess.getstatusoutput('pwd')
>>> ret
(0, '/test01')

#4、返回结果为 字符串 类型
>>> ret = subprocess.getoutput('ls -a')
>>> ret
'.\n..\ntest.py'


#5、返回结果为'bytes'类型
>>> res=subprocess.check_output(['ls','-l'])
>>> res.decode('utf8')
'总用量 4\n-rwxrwxrwx. 1 root root 334 11月 21 09:02 test.py\n'

将dos格式文件转换成unix格式

subprocess.check_output(['chmod', '+x', filepath])
subprocess.check_output(['dos2unix', filepath])

2、subprocess.Popen()

  1. 实际上,上面的几个函数都是基于Popen()的封装(wrapper),这些封装的目的在于让我们容易使用子进程
  2. 当我们想要更个性化我们的需求的时候,就要转向Popen类,该类生成的对象用来代表子进程
  3. 与上面的封装不同,Popen对象创建后,主程序不会自动等待子进程完成。我们必须调用对象的wait()方法,父进程才会等待 (也就是阻塞block)
  4. 从运行结果中看到,父进程在开启子进程之后并没有等待child的完成,而是直接运行print。

child.wait()等待子进程执行

#1、先打印'parent process'不等待child的完成
import subprocess
child = subprocess.Popen(['ping','-c','4','www.baidu.com'])
print('parent process')

#2、后打印'parent process'等待child的完成
import subprocess
child = subprocess.Popen('ping -c4 www.baidu.com',shell=True)
child.wait()
print('parent process')

child.poll() # 检查子进程状态
   child.kill() # 终止子进程
   child.send_signal() # 向子进程发送信号
   child.terminate() # 终止子进程

3、subprocess.PIPE 将多个子进程的输入和输出连接在一起

  1. subprocess.PIPE实际上为文本流提供一个缓存区。child1的stdout将文本输出到缓存区,随后child2的stdin从该PIPE中将文本读取走
  2. child2的输出文本也被存放在PIPE中,直到communicate()方法从PIPE中读取出PIPE中的文本。
  3. 注意:communicate()是Popen对象的一个方法,该方法会阻塞父进程,直到子进程完成

分步执行cat /etc/passwd | grep root命令

import subprocess
#下面执行命令等价于: cat /etc/passwd | grep root
child1 = subprocess.Popen(["cat","/etc/passwd"], stdout=subprocess.PIPE)
child2 = subprocess.Popen(["grep","root"],stdin=child1.stdout, stdout=subprocess.PIPE)
out = child2.communicate()               #返回执行结果是元组
print(out)
#执行结果: (b'root:x:0:0:root:/root:/bin/bash\noperator:x:11:0:operator:/root:/sbin/nologin\n', None)

获取ping命令执行结果

import subprocess

list_tmp = []
def main():
    p = subprocess.Popen(['ping', 'www.baidu.com', '-c5'], stdin = subprocess.PIPE, stdout = subprocess.PIPE)
    while subprocess.Popen.poll(p) == None:
        r = p.stdout.readline().strip().decode('utf-8')
        if r:
            # print(r)
            v = p.stdout.read().strip().decode('utf-8')
            list_tmp.append(v)
main()
print(list_tmp[0])

十二、logging模块

1、logging模块的作用

  1. 很多程序都有记录日志的需求,并且日志中包含的信息即有正常的程序访问日志,还可能有错误、警告等信息输出
    2. python的logging模块提供了标准的日志接口,你可以通过它存储各种格式的日志
    3. logging的日志可以分为 debug(), info(), warning(), error() and critical() 5个级别
Level When it’s used
DEBUG Detailed information, typically of interest only when diagnosing problems.(详细的信息,通常只有在诊断问题时才感兴趣。)
INFO Confirmation that things are working as expected.(确认事情正在按预期工作。)
WARNING An indication that something unexpected happened, or indicative of some problem in the near future (e.g. ‘disk space low’). The software is still working as expected.(意外事件发生的迹象,或在不久的将来出现问题的迹象(如“磁盘空间不足”)。软件仍在正常工作。)
ERROR Due to a more serious problem, the software has not been able to perform some function.(由于更严重的问题,软件无法执行某些功能。)
CRITICAL A serious error, indicating that the program itself may be unable to continue running.(一个严重的错误,表明程序本身可能无法继续运行。)

2、日志格式

%(name)s Logger的名字
%(levelno)s 数字形式的日志级别
%(levelname)s 文本形式的日志级别
%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
%(filename)s 调用日志输出函数的模块的文件名
%(module)s 调用日志输出函数的模块名
%(funcName)s 调用日志输出函数的函数名
%(lineno)d 调用日志输出函数的语句所在的代码行
%(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
%(message)s 用户输出的消息

3、打印日志和将日志写入文件小例子

将日志打印到屏幕

import logging
#1 将日志信息打印到屏幕中
logging.debug('debug info')
logging.info('info')
logging.warning('warning info')
logging.error('error info')
logging.critical('critical info')

将日志记录到文件

import logging
logging.basicConfig(filename='test.log',level=logging.INFO,format='%(levelname)s  %(asctime)s %(message)s',datefmt='%Y-%m-%d %H:%M-%S')
logging.info('I am info')
# 记录的文件的日志格式:   INFO  2017-11-26 12:54-04 I am info

4、同时把log打印在屏幕和文件日志里

1. Python 使用logging模块记录日志涉及四个主要类
1. logger提供了应用程序可以直接使用的接口;

2. handler将(logger创建的)日志记录发送到合适的目的输出;

3. filter提供了细度设备来决定输出哪条日志记录;

4. formatter决定日志记录的最终输出格式
2. 第一个主要类:logger
1. 每个程序在输出信息之前都要获得一个Logger。

2. Logger通常对应了程序的模块名,比如聊天工具的图形界面模块可以这样获得它的Logger:LOG=logging.getLogger(”chat.gui”)

3. 而核心模块可以这样:LOG=logging.getLogger(”chat.kernel”)

4. Logger.setLevel(lel):指定最低的日志级别,低于lel的级别将被忽略。debug是最低的内置级别,critical为最高

5. Logger.addFilter(filt)、Logger.removeFilter(filt):添加或删除指定的filter

6. Logger.addHandler(hdlr)、Logger.removeHandler(hdlr):增加或删除指定的handler

7. Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():可以设置的日志级别
3. 第二个主要类:handler
1. handler对象负责发送相关的信息到指定目的地,Python的日志系统有多种Handler可以使用。

2. Handler可以把信息输出到控制台,有些Logger可以把信息输出到文件,还有些 Handler可以把信息发送到网络上

3. 如果觉得不够用,还可以编写自己的Handler,可以通过addHandler()方法添加多个多handler

    1)Handler.setLevel(lel):指定被处理的信息级别,低于lel级别的信息将被忽略

    2)Handler.setFormatter():给这个handler选择一个格式

    3)Handler.addFilter(filt)、Handler.removeFilter(filt):新增或删除一个filter对象  
4. 每个Logger可以附加多个Handler,这里介绍一些常用的
1. logging.StreamHandler
	1). 使用这个Handler可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息。
	2). 它的构造函数是: StreamHandler([strm]) 其中strm参数是一个文件对象。默认是sys.stderr

2. logging.FileHandler

	1). 和StreamHandler类似,用于向一个文件输出日志信息,不过FileHandler会帮你打开这个文件

	2). 它的构造函数是:

        ① FileHandler(filename[,mode])

    	② filename是文件名,必须指定一个文件名

		③ mode是文件的打开方式。参见Python内置函数open()的用法。默认是’a',即添加到文件末尾。

3. logging.handlers.RotatingFileHandler

	1). 这个Handler类似于上面的FileHandler,但是它可以管理文件大小。

	2). 当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建 一个新的同名日志文件继续输出

	3). 比如日志文件是chat.log。当chat.log达到指定的大小之后,RotatingFileHandler自动把文件改名为chat.log.1

	4). 不过,如果chat.log.1已经存在,会先把chat.log.1重命名为chat.log.2。。。最后重新创建 chat.log,继续输出日志信息

	5). 它的构造函数是:RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
        ①其中filename和mode两个参数和FileHandler一样
        ②maxBytes用于指定日志文件的最大文件大小,如果maxBytes为0,意味着日志文件可以无限大这时上面描述的重命名过程就不会发生
        ③backupCount用于指定保留的备份文件的个数。比如,如果指定为2,当上面描述的重命名过程发生时,原有的chat.log.2并不会被更名,而是被删除。
        
4. logging.handlers.TimedRotatingFileHandler**

	1). 这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就 自动创建新的日志文件。

	2). 过新的文件不是附加数字,而是当前时间。它的构造函数是:
        ①TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
        ②其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。
        ③interval是时间间隔。
        ④when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:

    注: S 秒;M 分;H 小时;D 天;W 每星期(interval==0时代表星期一);midnight 每天

同时把log打印在屏幕和文件日志里

import logging
#1、 create logger
logger1 = logging.getLogger('TEST-LOG')      #这里的logger1是创建的logger实例名称
logger1.setLevel(logging.DEBUG)                #这里设置只有在DEBUG及其以上级别才会记录

#2、 create console handler and set level to debug
ch = logging.StreamHandler()               #StreamHandler括号内无参数表示默认是sys.stderr
ch.setLevel(logging.DEBUG)                   #指定只有在DEBUG级别及以上的才会打印到屏幕

#3、 create file handler and set level to warning
fh = logging.FileHandler("access.log",encoding="utf-8")    #与StreamHandler类似但是必须指定记录日志文件名
fh.setLevel(logging.WARNING)                                 #指定在WARNING级别及以上的才会记录到文件中

#4、 create formatter                    #指定记录日志的格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

#5、 add formatter to ch and fh
ch.setFormatter(formatter)                #ch为刚刚创建的StreamHandler方法这里指定使用formatter的格式
fh.setFormatter(formatter)                #fh为刚刚创建的FileHandler方发使用刚创建的formatter日志格式

#6、 add ch and fh to logger
logger1.addHandler(ch)                    #将刚刚创建的StreamHandler方法添加到刚刚新建的日志实例logger1中
logger1.addHandler(fh)                    #将刚刚创建的FileHandler方法添加到刚刚新建的日志实例logger1中

#7、 'application' code
logger1.debug('debug message')
logger1.info('info message')
logger1.warn('warn message')
logger1.error('error message')
logger1.critical('critical message')

# 运行结果:打印在屏幕中的信息是下面五条
# 2017-01-07 09:32:08,478 - TEST-LOG - DEBUG - debug message
# 2017-01-07 09:32:08,479 - TEST-LOG - INFO - info message
# 2017-01-07 09:32:08,479 - TEST-LOG - WARNING - warn message
# 2017-01-07 09:32:08,479 - TEST-LOG - ERROR - error message
# 2017-01-07 09:32:08,480 - TEST-LOG - CRITICAL - critical message
# 记录到access.log的文件内容是这里的三条
# 2017-01-08 12:21:26,398 - TEST-LOG - WARNING - warn message
# 2017-01-08 12:21:26,398 - TEST-LOG - ERROR - error message
# 2017-01-08 12:21:26,398 - TEST-LOG - CRITICAL - critical message

log日志自动截断代码展示

import logging

from logging import handlers

logger = logging.getLogger(__name__)

log_file = "timelog.log"

#1、根据日志文件大小切分:当文件大于10字节就会创建一个timelog.log.1 这样名字的文件存放后续日志
# fh = handlers.RotatingFileHandler(filename=log_file,maxBytes=10,backupCount=3)

#2、根据时间间隔切分: 每次间隔5秒就会重新创建一个timelog.log.2017-11-21_15-09-46 这样名字的文件存放后续日志
fh = handlers.TimedRotatingFileHandler(filename=log_file,when="S",interval=5,backupCount=3)

formatter = logging.Formatter('%(asctime)s %(module)s:%(lineno)d %(message)s')

fh.setFormatter(formatter)

logger.addHandler(fh)

logger.warning("test1")
logger.warning("test1")

# 运行结果:
#1. 根据日志文件大小切分:当存放日志的文件大于10字节就会从新创建新文件存放
#2. 根据时间间隔切分: 每隔5秒就会自动创建一个新文件存放

5、项目使用举例:记录错误日志和运行日志

lib/log.py

import os
import logging
from config import settings


class Logger(object):
    __instance = None

    def __init__(self):
        self.run_log_file = settings.RUN_LOG_FILE
        self.error_log_file = settings.ERROR_LOG_FILE
        self.run_logger = None
        self.error_logger = None

        self.initialize_run_log()
        self.initialize_error_log()

    def __new__(cls, *args, **kwargs):
        if not cls.__instance:
            cls.__instance = object.__new__(cls, *args, **kwargs)
        return cls.__instance

    @staticmethod
    def check_path_exist(log_abs_file):
        log_path = os.path.split(log_abs_file)[0]
        if not os.path.exists(log_path):
            os.mkdir(log_path)

    def initialize_run_log(self):
        self.check_path_exist(self.run_log_file)
        file_1_1 = logging.FileHandler(self.run_log_file, 'a', encoding='utf-8')
        fmt = logging.Formatter(fmt="%(asctime)s - %(levelname)s :  %(message)s")
        file_1_1.setFormatter(fmt)
        logger1 = logging.Logger('run_log', level=logging.INFO)
        logger1.addHandler(file_1_1)
        self.run_logger = logger1

    def initialize_error_log(self):
        self.check_path_exist(self.error_log_file)
        file_1_1 = logging.FileHandler(self.error_log_file, 'a', encoding='utf-8')
        fmt = logging.Formatter(fmt="%(asctime)s  - %(levelname)s :  %(message)s")
        file_1_1.setFormatter(fmt)
        logger1 = logging.Logger('run_log', level=logging.ERROR)
        logger1.addHandler(file_1_1)
        self.error_logger = logger1

    def log(self, message, mode=True):
        """
        写入日志
        :param message: 日志信息
        :param mode: True表示运行信息,False表示错误信息
        :return:
        """
        if mode:
            self.run_logger.info(message)
        else:
            self.error_logger.error(message)

settings.py

# 错误日志
ERROR_LOG_FILE = os.path.join(BASEDIR, "log", 'error.log')
# 运行日志
RUN_LOG_FILE = os.path.join(BASEDIR, "log", 'run.log')

run.py 记录日志

from lib.log import Logger
Logger().log('成功创建',True)   # 运行日志
Logger().log('创建失败',False)  # 错误日志

13 paramiko使用

在windows中安装paramiko: pip install paramiko

1、linux中scp命令的使用
ssh [email protected]10.1.0.51            #ssh远程登录

scp -rp aa.txt [email protected]10.1.0.50:/tmp/       #将本地aa.txt文件复制到10.1.0.50的/tmp文件夹中 
2、Paramiko模块作用

1)如果需要使用SSH从一个平台连接到另外一个平台,进行一系列的操作时,

**比如:**批量执行命令,批量上传文件等操作,paramiko是最佳工具之一。

2)paramiko是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接

3)由于使用的是python这样的能够跨平台运行的语言,所以所有python支持的平台,如Linux, Solaris, BSD,MacOS X, Windows等,paramiko都可以支持

4)如果需要使用SSH从一个平台连接到另外一个平台,进行一系列的操作时,paramiko是最佳工具之一

5)现在如果需要从windows服务器上下载Linux服务器文件:

a. 使用paramiko可以很好的解决以上问题,它仅需要在本地上安装相应的软件(python以及PyCrypto)
      b. 对远程服务器没有配置要求,对于连接多台服务器,进行复杂的连接操作特别有帮助。

3、paramiko基于用户名密码连接

远程执行命令

import paramiko

# 1 创建SSH对象
ssh = paramiko.SSHClient()
# 2 允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 3 连接服务器
ssh.connect(hostname='1.1.1.3', port=22, username='root', password='[email protected]')

# 4 执行命令                                         #stdin标准输入: 自己输入的命令
stdin, stdout, stderr = ssh.exec_command('pwd')      # stdout标准输出:  命令执行结果
# 5 获取命令结果                                     #stderr标准错误:  命令执行报错的结果
res, err = stdout.read(), stderr.read()
result = res if res else err
print(result.decode())                              #运行结果: /root

# 6 关闭连接
ssh.close()

SFTPClient实现对Linux服务器上传和下载

import paramiko

#1 连接客户端
transport = paramiko.Transport(('10.1.0.50',22))
transport.connect(username='root',password='[email protected]')

#2 定义与客户端交互    将刚刚定义的transport当参数传递给他
sftp = paramiko.SFTPClient.from_transport(transport)
#3 将location.py 上传至服务器 /tmp/test.py
sftp.put(r'C:\bbb\file.txt', '/tmp/file.txt')

#4 将remove_path 下载到本地 local_path
sftp.get('/tmp/file.txt',r'C:\bbb\file.txt')

#5 关闭连接
transport.close()

4、在两台Linux中演示无密码ssh登陆对方

1、使用ssh-copy-id命令将公钥copy到被管理服务器中(法1:简单)

1)**操作目的:**在10.1.0.50的tom用户下生成秘钥对,将生成的私钥用ssh-copy-id拷贝给10.1.0.51的root用户,那么root用户就可以使用 ssh [email protected] 远程登陆了

ssh-******生成秘钥

[[email protected] .ssh]$ ssh-****** 
Generating public/private rsa key pair.
Enter file in which to save the key (/home/tom/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/tom/.ssh/id_rsa.
Your public key has been saved in /home/tom/.ssh/id_rsa.pub.

​ 2)执行完上面命令后再 /home/tom/.ssh 文件夹下生成了公钥私钥连个文件: id_rsa id_rsa.pub

3)将在10.1.0.50中生成的公钥复制到10.1.0.51的root加目录下:

ssh-copy-id [email protected]

4)执行完成后就会在10.1.0.51中生成 /home/zhangsan/.ssh/ authorized_keys 文件

5)此时输入: ssh [email protected] 就可以直接不用密码登陆了

2、手动创建秘钥并手动copy到被管理服务器(法2:较复杂)

1)使用10.1.0.51在不输入密码的情况下ssh链接到10.1.0.50,使用10.1.0.50的tom用户身份进行登录

2)在 10.1.0.51上创建用于认证的秘钥对

ssh-******生成秘钥对

[[email protected] /]# ssh-****** 
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_rsa.        #存放私钥 的路径
Your public key has been saved in /root/.ssh/id_rsa.pub.        #存放公约 的路径
注:将10.1.0.51上生成的**对中的公钥放到10.1.0.50的服务器tom用户家目录/home/tom/.ssh/authorized_keys 中,就可以在10.1.0.51中无密码登陆10.1.0.50

​ 3)在10.1.0.51中生成的私钥路径:cat ~/.ssh/id_rsa.pub

4)在被登录服务器中创建用户tom,将刚刚在10.1.0.51上生成的私钥内容放到10.1.0.50的/home/tom/.ssh/authorized_keys中,

5)新创建用户没用ssh登录过时没有,可以手动创建

手动创建.ssh中的文件

1、mkdir /home/tom/.ssh                             #创建/home/tom/.ssh目录

2、chmod 700 /home/tom/.ssh/                          #将目录权限改为 700

3、touch /home/tom/.ssh/authorized_keys               #创建/home/tom/.ssh/authorized_keys文件

4、chmod 600 /home/tom/.ssh/authorized_keys            #将文件权限改为600

5、将10.1.0.51的公钥文件粘贴到10.1.0.50/home/tom/.ssh/authorized_keys中

​ 6)完成上面几步后就可以在10.1.0.51上无密码登陆10.1.0.50了

7)登陆命令: ssh [email protected]

5、paramiko基于公钥**连接:(ssh_rsa)

  1. **操作目的:**在10.1.0.50中生成公钥和私钥,然后将生成的公钥放到10.1.0.51的winuser的/home/zhangsan/.ssh/ authorized_keys 目录下
  2. 第一步:在10.1.0.50中创建anyuser,在10.1.0.51中创建winuser
  3. 在10.1.0.50中使用anyuser登陆,然后生成公钥和私钥

anyuser生成秘钥对

[[email protected] ~]$ ssh-****** 
Generating public/private rsa key pair.

Enter file in which to save the key (/home/anyuser/.ssh/id_rsa): Created directory '/home/anyuser/.ssh'.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/anyuser/.ssh/id_rsa.
Your public key has been saved in /home/anyuser/.ssh/id_rsa.pub.

​ 4. 在10.1.0.50中生成的公钥复制到10.1.0.51的winuser目录下: ssh-copy-id [email protected]

  1. 执行完ssh-copy-id命令后就可以看到在10.1.0.51中新加了这样的目录和文件/home/zhangsan/.ssh/ authorized_keys # authorized_keys就是刚刚在10.1.0.50中生成的私钥
  2. 将10.1.0.50中生成秘钥文件内容放到windows的PyCharm运行文件同目录,随便命名为:id_rsa50.txt

用PyCharm基于公钥**执行命令

import paramiko

# 1 指定公钥所在本地的路径
private_key = paramiko.RSAKey.from_private_key_file('id_rsa50.txt')

# 2 创建SSH对象
ssh = paramiko.SSHClient()
# 3 允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 4 连接服务器
ssh.connect(hostname='10.1.0.51', port=22, username='winuser', pkey=private_key)

# 5 执行命令
stdin, stdout, stderr = ssh.exec_command('pwd')  # stdout标准输出:  命令执行结果
# 6 获取命令结果                                          #stderr标准错误:  命令执行报错的结果
res, err = stdout.read(), stderr.read()
result = res if res else err
print(result.decode())
# 7 关闭连接
ssh.close()

用PyCharm基于公钥**上传下载

import paramiko
#1 指定公钥所在本地的路径
private_key = paramiko.RSAKey.from_private_key_file('id_rsa50.txt')

#2 连接客户端
transport = paramiko.Transport(('10.1.0.51', 22))
transport.connect(username='winuser', pkey=private_key )
#3 定义与客户端交互
sftp = paramiko.SFTPClient.from_transport(transport)

#4上传 将本地test1.py 上传至服务器 /tmp/test1.py
sftp.put('test1.py', '/tmp/test1.py')

#5下载 将服务器/tmp/test1.py文件 下载到本地C:\bbb\test1.txt
sftp.get('/tmp/test1.py', r'C:\bbb\test1.txt')

transport.close()

十四、re模块

1、常用正则表达式符号

⒈. 通配符( . )

**作用:**点(.)可以匹配除换行符以外的任意一个字符串

例如:‘.ython’ 可以匹配‘aython’ ‘bython’ 等等,但只能匹配一个字符串

⒉. 转义字符(\ )

**作用:**可以将其他有特殊意义的字符串以原本意思表示

例如:‘python.org’ 因为字符串中有一个特殊意义的字符串(.)所以如果想将其按照普通意义就必须使用这样表示: ‘python.org’ 这样就只会匹配‘python.org’ 了

**注:**如果想对反斜线(\)自身转义可以使用双反斜线([\)这样就表示](file://xn–)-ml2b386a07qelrrgk/) ’\’

⒊. 字符集

**作用:**使用中括号来括住字符串来创建字符集,字符集可匹配他包括的任意字串

‘[pj]ython’ 只能够匹配‘python’ ‘jython’

‘[a-z]’ 能够(按字母顺序)匹配a-z任意一个字符

‘[a-zA-Z0-9]’ 能匹配任意一个大小写字母和数字

‘[^abc]’ 可以匹配任意除a,b和c 之外的字符串

⒋. 管道符

**作用:**一次性匹配多个字符串

例如:’python|perl’ 可以匹配字符串‘python’ 和 ‘perl’

⒌. 可选项和重复子模式(在子模式后面加上问号?)

**作用:**在子模式后面加上问号,他就变成可选项,出现或者不出现在匹配字符串中都是合法的

**例如:**r’(aa)?(bb)?ccddee’ 只能匹配下面几种情况

‘aabbccddee’

‘aaccddee’

‘bbccddee’

‘ccddee’

⒍. 字符串的开始和结尾

‘w+’ 匹配以w开通的字符串

‘^http’ 匹配以’http’ 开头的字符串

‘ $com’ 匹配以‘com’结尾的字符串

7.最常用的匹配方法

\d 匹配任何十进制数;它相当于类 [0-9]。
       \D 匹配任何非数字字符;它相当于类 [^0-9]。
       \s 匹配任何空白字符;它相当于类 [ fv]。
       \S 匹配任何非空白字符;它相当于类 [^ fv]。
       \w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
       \W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]。

\w* 匹配所有字母字符

\w+ 至少匹配一个字符

re模块更详细表达式符号

'.'         默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
'^'         匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)
'$'         匹配字符结尾,或e.search("foo$","bfoo\nsdfsf",flags=re.MULTILINE).group()也可以
'*'         匹配*号前的字符0次或多次,re.findall("ab*","cabb3abcbbac")  结果为['abb', 'ab', 'a']
'+'         匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb']
'?'         匹配前一个字符1次或0'{m}'       匹配前一个字符m次
'{n,m}'     匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb']
'|'         匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC'
'(...)'     分组匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 结果 abcabca456c 
'\A'       只从字符开头匹配,re.search("\Aabc","alexabc") 是匹配不到的
'\Z'       匹配字符结尾,同$
'\d'       匹配数字0-9
'\D'       匹配非数字
'\w'       匹配[A-Za-z0-9]
'\W'       匹配非[A-Za-z0-9]
's'        匹配空白字符、\t、\n、\r , re.search("\s+","ab\tc1\n3").group() 结果 '\t'
\b           匹配一个单词边界,也就是指单词和空格间的位置,如,“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”
\B           匹配非单词边界。“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”

2、re模块常用函数

函数 描述
compile(pattern[, flags]) 根据正则表达式字符串创建模式对象
search(pattern, string[, flags]) 在字符串中寻找模式
match(pattern, 常用模块[, flags]) 在字符串的开始处匹配模式
split(pattern, string[, maxsplit=0]) 根据模式的匹配项来分割字符串
findall(pattern, string) 列出字符串中模式的所有匹配项并以列表返回
sub(pat, repl, string[, count=0]) 将字符串中所有pat的匹配项用repl替换
escape(string) 将字符串中所有特殊正则表达式字符转义
1.  re.compile(pattern[, flags])

1)把一个正则表达式pattern编译成正则对象,以便可以用正则对象的match和search方法

2)用了re.compile以后,正则对象会得到保留,这样在需要多次运用这个正则对象的时候,效率会有较大的提升

re.compile使用

import re
mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
ret = re.match(mobile_re,'18538762511')
print(ret)            # <_sre.SRE_Match object; span=(0, 11), match='18538652511'>

2. search(pattern, string[, flags]) match(pattern, string[, flags])

**1)**match :只从字符串的开始与正则表达式匹配,匹配成功返回matchobject,否则返回none;

**2)**search :将字符串的所有字串尝试与正则表达式匹配,如果所有的字串都没有匹配成功,返回none,否则返回matchobject;

match与search使用比较

import re
a =re.match('www.bai', 'www.baidu.com')
b = re.match('bai', 'www.baidu.com')
print(a.group())                                # www.bai
print(b)                                        # None

# 无论有多少个匹配的只会匹配一个
c = re.search('bai', 'www.baidubaidu.com')
print(c)                                        # <_sre.SRE_Match object; span=(4, 7), match='bai'>
print(c.group())                                # bai

⒊. split(pattern, string[, maxsplit=0])

**作用:**将字符串以指定分割方式,格式化成列表

split使用

import re
text = 'aa 1bb###2cc3ddd'
print(re.split('\W+', text))        # ['aa', '1bb', '2cc3ddd']
print(re.split('\W', text))          # ['aa', '1bb', '', '', '2cc3ddd']
print(re.split('\d', text))           # ['aa ', 'bb###', 'cc', 'ddd']
print(re.split('#', text))            # ['aa 1bb', '', '', '2cc3ddd']
print(re.split('#+', text))          # ['aa 1bb', '2cc3ddd']

⒋. findall(pattern, string)

**作用:**正则表达式 re.findall 方法能够以列表的形式返回能匹配的子串

findall使用

import re
p = re.compile(r'\d+')
print(p.findall('one1two2three3four4'))             # ['1', '2', '3', '4']
print(re.findall('o','one1two2three3four4'))        # ['o', 'o', 'o']
print(re.findall('\w+', 'he.llo, wo#rld!'))         # ['he', 'llo', 'wo', 'rld']

⒌. sub(pat, repl, string[, count=0])

**1)**替换,将string里匹配pattern的部分,用repl替换掉,最多替换count次然后返回替换后的字符串

**2)**如果string里没有可以匹配pattern的串,将被原封不动地返回

​ **3)**repl可以是一个字符串,也可以是一个函数

4) 如果repl是个字符串,则其中的反斜杆会被处理过,比如 \n 会被转成换行符,反斜杆加数字会被替换成相应的组,比如 \6 表示pattern匹配到的第6个组的内容

sub使用

import re
test="Hi, nice to meet you where are you from?"
print(re.sub(r'\s','-',test))          # Hi,-nice-to-meet-you-where-are-you-from?
print(re.sub(r'\s','-',test,5))        # Hi,-nice-to-meet-you-where are you from?
print(re.sub('o','**',test))           # Hi, nice t** meet y**u where are y**u fr**m?

⒍. escape(string)

1) re.escape(pattern) 可以对字符串中所有可能被解释为正则运算符的字符进行转义的应用函数。

2) 如果字符串很长且包含很多特殊技字符,而你又不想输入一大堆反斜杠,或者字符串来自于用户(比如通过raw_input函数获取输入的内容), 且要用作正则表达式的一部分的时候,可以用这个函数

escape使用

import re
print(re.escape('www.python.org'))

3、re模块中的匹配对象和组 group()

1)group方法返回模式中与给定组匹配的字符串,如果没有给定匹配组号,默认为组0

2)m.group() == m.group(0) == 所有匹配的字符

group(0)与group(1)区别比较

import re
a = "123abc321efg456"
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(0))    # 123abc321
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).groups())    # ('123', 'abc', '321')
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1))    # 123
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(2))    # abc
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(3))    # 321


import re
m = re.match('(..).*(..)(..)','123456789')
print(m.group(0))              # 123456789
print(m.group(1))              # 12
print(m.group(2))              # 67
print(m.group(3))              # 89

group()匹配之返回匹配索引

import re
m = re.match('www\.(.*)\..*','www.baidu.com')
print(m.group(1))           # baidu
print(m.start(1))             # 4
print(m.end(1))             # 9
print(m.span(1))            # (4, 9)

group()匹配ip,状态以元组返回

import re
test = 'dsfdf 22 g2323  GigabitEthernet0/3        10.1.8.1        YES NVRAM up eee'
# print(re.match('(\w.*\d)\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+YES\s+NVRAM\s+(\w+)\s+(\w+)\s*', test).groups())

ret = re.search(  r'(\w*\/\d+).*\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}).*(\s+up\s+)',test ).groups()
print(ret)          # 运行结果: ('GigabitEthernet0/3', '10.1.8.1', ' up ')

#1. (\w*\d+\/\d+)      匹配结果为:GigabitEthernet0/3
#1.1   \w*: 匹配所有字母数字     
#1.2   /\d+:匹配所有斜杠开头后根数字 (比如:/3 )

#2. (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})  匹配结果为:10.1.8.1

#3. \s+up\s+   匹配结果为: up 这个单词,前后都为空格

4、re模块其他知识点

re匹配忽略大小写,匹配换行

import re
#匹配时忽略大小写
print(re.search("[a-z]+","abcdA").group())                #abcd
print(re.search("[a-z]+","abcdA",flags=re.I).group())            #abcdA
#连同换行符一起匹配:
#'.'默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
print(re.search(r".+","\naaa\nbbb\nccc").group())            #aaa
print(re.search(r".+","\naaa\nbbb\nccc",flags=re.S))            
        #<_sre.SRE_Match object; span=(0, 12), match='\naaa\nbbb\nccc'>
print(re.search(r".+","\naaa\nbbb\nccc",flags=re.S).group())
                                                                               

计算器用到的几个知识点

1)init_l=[i for i in re.split('(\-\d+\.*\d*)',expression) if i]
        a. 按照类似负数的字符串分割成列表
        b. \-\d+\.*\d*是为了可以匹配浮点数(比如:3.14)
        c.if i)是为了去除列表中的空元素
        d. 分割结果:['-1', '-2', '*((', '-60', '+30+(',
2)re.search('[\+\-\*\/\(]$',expression_l[-1])
        a. 匹配expression_l列表最后一个元素是 +,-,*,/,( 这五个符号就是负数
3)new_l=[i for i in re.split('([\+\-\*\/\(\)])',exp) if i]
        a. 将字符串按照+,-,*,/,(,)切分成列表(不是正真的负数就切分)
4print(re.split('([\+\-])','-1+2-3*(2*2+3)'))            #按照加号或者减号分割成列表
运行结果: ['', '-', '1', '+', '2', '-', '3*(2*2', '+', '3)']
相关标签: python基础