python自动化编程-第五天
python自动化编程-第五天 模块
一、模块
1、定义:
模块:用来从逻辑上组织python代码(变量,函数,类,逻辑;作用是实现某一个功能),本质上就是.py结尾的python文件(文件名:test.py,对应的模块名就是test)
包:用来从逻辑上组织模块,本质就是一个目录(但是必须带有一个__init__.py文件)
2、导入方法
import modue_name #导入单个模块
import modue1_name,module2_name #导入多个模块
from module_name import [*|func_name|变量]
#本质是将module_name的文件中的代码复制到脚本此处,并解释一遍
from module_name import func1_name,func2_name
#导入一个模块的多个函数
from module_name import logger as logger_test
#用as定义一个别名
3、import本质(路径搜索和搜索路径)
import modue_name
import的本质就是将module_name运行(解释)了一遍,然后将所有的代码,赋值给了module_name这个变量;
调用方法:module_name.func_name
from module_name import func_name
本质就是把module_name模块的func_name[变量|函数],在from module_name这个位置解释一遍;相当于将func_name的代码复制到import的位置。
调用方法:func_name
导入模块的本质就是把python文件解释一遍
导入包的本质就是执行该包下的__init__.py文件
import module_name ---->module_name.py---->module_name.py的路径--->sys.path
导入包与导入模块是不一样的!
导入包,要在__init__.py中导入模块,例如:form . import test1(使用相对导入),其中test1.py是一个模块,这样在导入包时,test1.py这个模块才能使用;
在其他目录导入包或模块时,需要用到from,例如
test
├──test1
│ └──test1.1
├──test2
│ └──test2.1
└──test3
要想在test2.1的脚本中调用test1.1,首先要将test目录加入到sys.path,然后使用from test1 import test1.1
这样就可以在test2.1中使用test1.1的代码了。
4、导入优化
from module_test import test
from主要是可以提高代码执行的效率,不需要每次都要找模块名
导入模块时,尽量使用from来导入;
5、模块的分类:
a.标准库
b.开源模块
c.自定义模块
二、time模块与datetime模块
https://docs.python.org/3.6/library/datetime.html#datetime.time
1、time模块
time模块中,时间有三种格式:
第一种是时间戳格式(以秒为单位,从1970年开始的秒数);
第二种是字符串格式;
第三种是时间元组格式,
三种格式可以相互转换;
>>> import time
>>> time.time()
1513156133.173734 #时间戳,单位是秒
>>> time.localtime()
time.struct_time(tm_year=2017, tm_mon=12, tm_mday=13, tm_hour=17, tm_min=11, tm_sec=26, tm_wday=2, tm_yday=347, tm_isdst=0) #时间元组格式,默认是当前的本地时间,也就是UTC+8的时间,因为中国是东八区,因此UTC+8;
>>> time.localtime(1513156133.173734)
time.struct_time(tm_year=2017, tm_mon=12, tm_mday=13, tm_hour=17, tm_min=8, tm_sec=53, tm_wday=2, tm_yday=347, tm_isdst=0) #time.localtime()的参数时时间戳;
sleep() #表示静默,单位是秒
>>> time.gmtime()
time.struct_time(tm_year=2017, tm_mon=12, tm_mday=13, tm_hour=9, tm_min=18, tm_sec=59, tm_wday=2, tm_yday=347, tm_isdst=0) #当前时间的元组格式,返回的是UTC时间
>>> time.gmtime(1513156133.173734)
time.struct_time(tm_year=2017, tm_mon=12, tm_mday=13, tm_hour=9, tm_min=8, tm_sec=53, tm_wday=2, tm_yday=347, tm_isdst=0) #指定时间戳的时间元组格式,返回的是UTC时间
# mktime():将元组的形式转换为时间戳,只接受一个参数,不能直接传递元组,可以将元组设置为一个变量传给给mktime();
>>> import time
>>> starttime = time.localtime()
>>> time.mktime(starttime)
1513227499.0
>>> starttime
time.struct_time(tm_year=2017, tm_mon=12, tm_mday=14, tm_hour=12, tm_min=58, tm_sec=19, tm_wday=3, tm_yday=348, tm_isdst=0)
>>>
# strftime(format,元组):还可以传递元组,就可以将元组的时间转换为字符串了;
>>> time.strftime("%Y-%m-%d %H:%M:%S") #元组不写,默认为当前时间
'2017-12-14 12:58:58'
>>> time.strftime("%Y-%m-%d %H:%M:%S",starttime)
'2017-12-14 12:58:19'
>>> starttime
time.struct_time(tm_year=2017, tm_mon=12, tm_mday=14, tm_hour=12, tm_min=58, tm_sec=19, tm_wday=3, tm_yday=348, tm_isdst=0)
>>>
# strptime(字符串,format):将字符串转换为元组:
>>> time.strptime('2017-12-14 12:28:58',"%Y-%m-%d %H:%M:%S")
time.struct_time(tm_year=2017, tm_mon=12, tm_mday=14, tm_hour=12, tm_min=28, tm_sec=58, tm_wday=6, tm_yday=337, tm_isdst=-1)
# asctime():将元组转换为字符串,该字符串有固定格式: '%c' 星期 月份 日 时间 年
>>> time.asctime(starttime)
'Thu Dec 14 12:58:19 2017'
# ctime():将时间戳转换为字符串,该字符串也有固定格式,与asctime()的格式一样;
>>> time.ctime(time.time())
'Thu Dec 14 13:23:54 2017'
取出时间元组的数据
>>> x = time.localtime()
>>> x.tm_year
2017 #取出年份
字符串格式的宏编码:
%a 本地简化星期名称
%A 本地完整星期名称
%b 本地简化月份名称
%B 本地完整月份名称
%c 本地相应的日期和时间表示
%d 一个月中的第几天(01 - 31)
%H 一天中的第几个小时(24小时制,00 - 23)
%I 第几个小时(12小时制,01 - 12)
%j 一年中的第几天(001 - 366)
%m 月份(01 - 12)
%M 分钟数(00 - 59)
%p 本地am或者pm的相应符 一
%S 秒(01 - 61) 二
%U 一年中的星期数。(00 - 53星期天是一个星期的开始。)第一个星期天之前的所有天数都放在第0周。
%w 一个星期中的第几天(0 - 6,0是星期天)
%W 和%U基本相同,不同的是%W以星期一为一个星期的开始。
%x 本地相应日期
%X 本地相应时间
%y 去掉世纪的年份(00 - 99)
%Y 完整的年份
%Z 时区的名字(如果不存在为空字符)
%% ‘%’字符

2、datetime模块
datetime模块实际上就是time模块的高级封装;
datetime.date.now() #当前日期
datatime.time.now() #当前时间
datatime.datatime.now() #当前日期和时间
class datetime.timedelta(days=0、 seconds=0、 microseconds=0、 milliseconds=0、 minutes=0、 hours=0、 weeks=0)
# 所有参数都是可选的, 默认为0。参数可以是整数或浮点型, 也可以是正的或负的。
例如:
import datetime,time
print(datetime.datetime.now()) #返回 2016-08-19 12:47:03.941925
print(datetime.date.fromtimestamp(time.time()) ) # 时间戳直接转成日期格式 2016-08-19
print(datetime.datetime.now() )
print(datetime.datetime.now() + datetime.timedelta(3)) #当前时间+3天
print(datetime.datetime.now() + datetime.timedelta(-3)) #当前时间-3天
print(datetime.datetime.now() + datetime.timedelta(hours=3)) #当前时间+3小时
print(datetime.datetime.now() + datetime.timedelta(minutes=30)) #当前时间+30分
# 输出:
2017-12-14 13:30:41.923147
2017-12-14
2017-12-14 13:30:41.923213
2017-12-17 13:30:41.923222
2017-12-11 13:30:41.923238
2017-12-14 16:30:41.923246
2017-12-14 14:00:41.923258
c_time = datetime.datetime.now()
print(c_time.replace(minute=3,hour=2)) #时间替换
三、random 模块
随机数模块
import random
print (random.random()) #0.6445010863311293
# random.random()用于生成一个0到1的随机符点数: 0 <= n < 1.0
print (random.randint(1,7)) #4
# random.randint()的函数原型为:random.randint(a, b),用于生成一个指定范围内的整数。
# 其中参数a是下限,参数b是上限,生成的随机数n: a <= n <= b
print (random.randrange(1,10)) #5
# random.randrange的函数原型为:random.randrange([start], stop[, step]),
# 从指定范围内,按指定基数递增的集合中 获取一个随机数。如:random.randrange(10, 100, 2),
# 结果相当于从[10, 12, 14, 16, ... 96, 98]序列中获取一个随机数。
# random.randrange(10, 100, 2)在结果上与 random.choice(range(10, 100, 2) 等效.
# stop -- 指定范围内的结束值,不包含在范围内。
print(random.choice('liukuni')) #i
# random.choice从序列中获取一个随机元素。
# 其函数原型为:random.choice(sequence)。参数sequence表示一个有序类型。
# 这里要说明一下:sequence在python不是一种特定的类型,而是泛指一系列的类型。
# list, tuple, 字符串都属于sequence。有关sequence可以查看python手册数据模型这一章。
# 下面是使用choice的一些例子:
print(random.choice("学习Python")) #学
print(random.choice(["JGood","is","a","handsome","boy"])) #List
print(random.choice(("Tuple","List","Dict"))) #List
print(random.sample([1,2,3,4,5],3)) #[1, 2, 5] 随机取3个
#random.sample的函数原型为:random.sample(sequence, k),从指定序列中随机获取指定长度的片断。sample函数不会修改原有序列。
print(random.uniform(1, 10)) #9.887001463194844 取1到10之间的随机浮点数
#洗牌
items = [1,2,3,4,5,6,7]
print(items) #[1, 2, 3, 4, 5, 6, 7]
random.shuffle(items)
print(items) #[1, 4, 7, 2, 5, 3, 6]
应用场景:随机验证码
import random
checkcode = ''
for i in range(4):
current = random.randrange(0,4)
#字母 ascii中65-90是大写字母,97-122是小写字母
if current == i:
tmp = chr(random.randint(65,90))
#数字
else:
tmp = random.randint(0,9)
checkcode += str(tmp)
print(checkcode)
四、os 模块
https://docs.python.org/3.6/library/os.html?highlight=os#module-os
OS模块主要用来处理与操作系统相关的操作
os.getcwd() #获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname") #改变当前脚本工作目录;相当于shell下cd
\\ 转义 \,
在字符串前加r
在Python的string前面加上‘r’, 是为了告诉编译器这个string是个raw string,不要转义backslash '\' 。 例如,\n 在raw string中,是两个字符,\和n, 而不会转意为换行符。由于正则表达式和 \ 会有冲突,因此,当一个字符串使用了正则表达式后,最好在前面加上'r'。
os.curdir #返回当前目录: ('.')
os.pardir #获取当前目录的父目录字符串名:('..')
os.makedirs('dirname1/dirname2') #可生成多层递归目录
os.removedirs('dirname1') #若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname') #生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname') #删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname') #列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove() #删除一个文件
os.rename("oldname","newname") #重命名文件/目录
os.stat('path/filename') #获取文件/目录信息
os.sep #输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
os.linesep #输出当前平台使用的行终止符,win下为"\r\n",Linux下为"\n"
os.pathsep #输出用于分割文件路径的字符串
os.popen #保存命令的执行结果输出,使用read()读出命令的结果,或者使用print打印到屏幕上,
os.name #输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
os.system("bash command") #运行shell命令,直接显示
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
os.path.isabs(path) #如果path是绝对路径,返回True
os.path.isfile(path) #如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path) #如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]]) #将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime(path) #返回path所指向的文件或者目录的最后存取时间
os.path.getmtime(path) #返回path所指向的文件或者目录的最后修改时间
os.path.getsize(filename) #返回filename文件的大小,单位字节,filename必须是绝对路径
五、sys 模块
https://docs.python.org/3.6/library/sys.html#module-sys
sys模块主要用来处理与python解析器相关的操作;
sys.argv 命令行参数List,第一个元素是程序本身路径
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]
六、shutil 模块
高级文件、文件夹、压缩包处理模块
shutil.copyfileobj(fsrc, fdst[, length])
将文件内容拷贝到另一个文件中,可以部分内容
shutil.copyfile(src, dst)
拷贝文件
shutil.copymode(src, dst)
仅拷贝权限。内容、组、用户均不变
shutil.copystat(src, dst)
拷贝状态的信息,包括:mode bits, atime, mtime, flags
shutil.copy(src, dst)
拷贝文件和权限
shutil.copy2(src, dst)
拷贝文件和状态信息
shutil.ignore_patterns(*patterns)
shutil.copytree(src, dst, symlinks=False, ignore=None)
递归的去拷贝文件
例如:copytree(source, destination, ignore=ignore_patterns('.pyc', 'tmp'))
shutil.rmtree(path[, ignore_errors[, onerror]])
递归的去删除文件
shutil.move(src, dst)
递归的去移动文件
shutil.make_archive(base_name, format,...)
创建压缩包并返回文件路径,例如:zip、tar
- base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
- 如:www =>保存至当前路径
- 如:/Users/wupeiqi/www =>保存至/Users/wupeiqi/
- format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
- root_dir: 要压缩的文件夹路径(默认当前目录)
- owner: 用户,默认当前用户
- group: 组,默认当前组
- logger: 用于记录日志,通常是logging.Logger对象
#将 /Users/wupeiqi/Downloads/test 下的文件打包放置当前程序目录
import shutil
ret = shutil.make_archive("wwwwwwwwww", 'gztar', root_dir='/Users/wupeiqi/Downloads/test')
#将 /Users/wupeiqi/Downloads/test 下的文件打包放置 /Users/wupeiqi/目录
import shutil
ret = shutil.make_archive("/Users/wupeiqi/wwwwwwwwww", 'gztar', root_dir='/Users/wupeiqi/Downloads/test')
shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的,详细:
import zipfile
# 压缩
z = zipfile.ZipFile('laxi.zip', 'w')
z.write('a.log')
z.write('data.data')
z.close()
# 解压
z = zipfile.ZipFile('laxi.zip', 'r')
z.extractall()
z.close()
import tarfile
# 压缩
tar = tarfile.open('your.tar','w')
tar.add('/Users/wupeiqi/PycharmProjects/bbs2.zip', arcname='bbs2.zip')
tar.add('/Users/wupeiqi/PycharmProjects/cmdb.zip', arcname='cmdb.zip')
tar.close()
# 解压
tar = tarfile.open('your.tar','r')
tar.extractall() # 可设置解压地址
tar.close()
七、json & pickle 模块
详见第四天的序列化和反序列化,
八、shelve 模块
shelve模块是一个简单的k,v将内存数据通过文件持久化的模块,可以持久化任何pickle可支持的python数据格式,只支持pickle格式;
import shelve
d = shelve.open('shelve_test') #打开一个文件
t = [1,2,3,4,5]
t2 = ‘hello world’
name = ["alex","rain","test"]
d["test"] = name #持久化列表
d["t1"] = t #持久化类
d["t2"] = t2
d.close()
#读取文件内容
print(d.get('test'))
print(d.get('t1'))
print(d.get('t2'))
九、XML 模块
xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单;xml还有些地方在使用;
xml的格式如下,就是通过<>节点来区别数据结构的:
<?xml version="1.0"?>
<data>
<country name="Liechtenstein">
<rank updated="yes">2</rank>
<year>2008</year>
<gdppc>141100</gdppc>
<neighbor name="Austria" direction="E"/>
<neighbor name="Switzerland" direction="W"/>
</country>
<country name="Singapore">
<rank updated="yes">5</rank>
<year>2011</year>
<gdppc>59900</gdppc>
<neighbor name="Malaysia" direction="N"/>
</country>
<country name="Panama">
<rank updated="yes">69</rank>
<year>2011</year>
<gdppc>13600</gdppc>
<neighbor name="Costa Rica" direction="W"/>
<neighbor name="Colombia" direction="E"/>
</country>
</data>
xml协议在各个语言里的都 是支持的,在python中可以用以下模块操作xml
import xml.etree.ElementTree as ET
tree = ET.parse("xmltest.xml")
root = tree.getroot()
print(root.tag)
#遍历xml文档
for child in root:
print(child.tag, child.attrib)
for i in child:
print(i.tag,i.text)
#只遍历year 节点
for node in root.iter('year'):
print(node.tag,node.text)
修改和删除xml文档的内容
import xml.etree.ElementTree as ET
tree = ET.parse("xmltest.xml")
root = tree.getroot()
#修改
for node in root.iter('year'):
new_year = int(node.text) + 1
node.text = str(new_year)
node.set("updated","yes")
tree.write("xmltest.xml")
#删除node
for country in root.findall('country'):
rank = int(country.find('rank').text)
if rank > 50:
root.remove(country)
tree.write('output.xml')
自己创建xml文档
import xml.etree.ElementTree as ET
new_xml = ET.Element("namelist")
name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"})
age = ET.SubElement(name,"age",attrib={"checked":"no"})
sex = ET.SubElement(name,"sex")
sex.text = '33'
name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"})
age = ET.SubElement(name2,"age")
age.text = '19'
et = ET.ElementTree(new_xml) #生成文档对象
et.write("test.xml", encoding="utf-8",xml_declaration=True)
ET.dump(new_xml) #打印生成的格式
十、PyYAML 模块
Python也可以很容易的处理ymal文档格式,只不过需要安装一个模块,参考资料:http://pyyaml.org/wiki/PyYAMLDocumentation
安装
pip3 install pyyaml
十一、ConfigParser 模块
用于生成和修改常见配置文档,当前模块的名称在 python 3.x 版本中变更为 configparser。
来看一个好多软件的常见文档格式如下
[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
[bitbucket.org]
User = hg
[topsecret.server.com]
Port = 50022
ForwardX11 = no
创建configparser文档
import configparser
config = configparser.ConfigParser()
config["DEFAULT"] = {'ServerAliveInterval': '45',
'Compression': 'yes',
'CompressionLevel': '9'}
config['bitbucket.org'] = {}
config['bitbucket.org']['User'] = 'hg'
config['topsecret.server.com'] = {}
topsecret = config['topsecret.server.com']
topsecret['Host Port'] = '50022' # mutates the parser
topsecret['ForwardX11'] = 'no' # same here
config['DEFAULT']['ForwardX11'] = 'yes'
with open('example.ini', 'w') as configfile:
config.write(configfile)
读取configparser文档
>>> import configparser
>>> config = configparser.ConfigParser()
>>> config.sections()
[]
>>> config.read('example.ini')
['example.ini']
>>> config.sections()
['bitbucket.org', 'topsecret.server.com']
>>> 'bitbucket.org' in config
True
>>> 'bytebong.com' in config
False
>>> config['bitbucket.org']['User']
'hg'
>>> config['DEFAULT']['Compression']
'yes'
>>> topsecret = config['topsecret.server.com']
>>> topsecret['ForwardX11']
'no'
>>> topsecret['Port']
'50022'
>>> for key in config['bitbucket.org']: print(key)
...
user
compressionlevel
serveraliveinterval
compression
forwardx11
>>> config['bitbucket.org']['ForwardX11']
'yes'
configparser文档的方法
[section1]
k1 = v1
k2:v2
[section2]
k1 = v1
import ConfigParser
config = ConfigParser.ConfigParser()
config.read('i.cfg')
# ########## 读 ##########
#secs = config.sections()
#print secs
#options = config.options('group2')
#print options
#item_list = config.items('group2')
#print item_list
#val = config.get('group1','key')
#val = config.getint('group1','key')
# ########## 改写 ##########
#sec = config.remove_section('group1')
#config.write(open('i.cfg', "w"))
#sec = config.has_section('wupeiqi')
#sec = config.add_section('wupeiqi')
#config.write(open('i.cfg', "w"))
#config.set('group2','k1',11111)
#config.write(open('i.cfg', "w"))
#config.remove_option('group2','age')
#config.write(open('i.cfg', "w"))
十二、hashlib 模块
用于加密相关的操作,3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法
使用场景:一般用于网站防篡改,ssl通用的是sha256
import hashlib
m = hashlib.md5()
m.update(b"Hello")
m.update(b"It's me")
print(m.digest())
m.update(b"It's been a long time since last time we ...")
print(m.digest()) #2进制格式hash
print(len(m.hexdigest())) #16进制格式hash
'''
def digest(self, *args, **kwargs): # real signature unknown
""" Return the digest value as a string of binary data. """
pass
def hexdigest(self, *args, **kwargs): # real signature unknown
""" Return the digest value as a string of hexadecimal digits. """
pass
'''
import hashlib
# ######## md5 ########
hash = hashlib.md5()
hash.update('admin')
print(hash.hexdigest())
# ######## sha1 ########
hash = hashlib.sha1()
hash.update('admin')
print(hash.hexdigest())
# ######## sha256 ########
hash = hashlib.sha256()
hash.update('admin')
print(hash.hexdigest())
# ######## sha384 ########
hash = hashlib.sha384()
hash.update('admin')
print(hash.hexdigest())
# ######## sha512 ########
hash = hashlib.sha512()
hash.update('admin')
print(hash.hexdigest())
十三、hmac 模块
散列消息鉴别码,简称HMAC,是一种基于消息鉴别码MAC(Message Authentication Code)的鉴别机制。使用HMAC时,消息通讯的双方,通过验证消息中加入的鉴别密钥K来鉴别消息的真伪;
一般用于网络通信中消息加密,前提是双方先要约定好key,就像接头暗号一样,然后消息发送把用key把消息加密,接收方用key + 消息明文再加密,拿加密后的值 跟 发送者的相对比是否相等,这样就能验证消息的真实性,及发送者的合法性了。
import hmac
h = hmac.new(b'天王盖地虎', b'宝塔镇河妖')
print h.hexdigest()
3个参数,key,加密的内容,加密算法
key和加密的内容都要是byte类型
hmac和hashlib的参数中如果有中文,则需要encode(编码)一下,
更多关于md5,sha1,sha256等介绍的文章看这里https://www.tbs-certificates.co.uk/FAQ/en/sha256.html
十四、subprocess 模块 --- 获取命令输入
允许您生成新的进程,连接到它们的输入/输出/错误管道,并获得它们的返回代码;主要用来替换以下模块:
os.system
os.spawn*
>>> subprocess.run(["ls", "-l"])
显示结果
>>> subprocess.run("ls -l",shell=True)
如果命令带有管道符,则需要把整个命令当做一个字符串来传递,并且需要shell=true这个参数,若没有管道符,则需要传递一个列表,而每个参数当做列表的一个元素来传递。
#执行命令,返回命令执行状态 , 0 or 非0
>>> retcode = subprocess.call(["ls", "-l"])
#执行命令,如果命令结果为0,就正常返回,否则抛异常
>>> subprocess.check_call(["ls", "-l"])
0
#接收字符串格式命令,返回元组形式,第1个元素是执行状态,第2个是命令结果
>>> subprocess.getstatusoutput('ls /bin/ls')
(0, '/bin/ls')
#接收字符串格式命令,并返回结果
>>> subprocess.getoutput('ls /bin/ls')
'/bin/ls'
#执行命令,并返回结果,注意是返回结果,不是打印,下例结果返回给res
>>> res=subprocess.check_output(['ls','-l'])
>>> res
b'total 0\ndrwxr-xr-x 12 alex staff 408 Nov 2 11:05 OldBoyCRM\n'
#上面那些方法,底层都是封装的subprocess.Popen
poll()
Check if child process has terminated. Returns returncode
返回命令执行状态,None表示没有执行完成,0表示执行完成
wait()
Wait for child process to terminate. Returns returncode attribute.
等待执行结果,直到出现结果;
terminate() 杀掉所启动进程
communicate() 等待任务结束,一般交互时使用
stdin 标准输入
stdout 标准输出
stderr 标准错误
pid
The process ID of the child process.
#例子
>>> p = subprocess.Popen("df -h|grep disk",stdin=subprocess.PIPE,stdout=subprocess.PIPE,shell=True)
>>> p.stdout.read()
b'/dev/disk1 465Gi 64Gi 400Gi 14% 16901472 104938142 14% /\n'
# subprocess.Popen 默认输出不是输出到屏幕上,必须在参数中指定下,stdout=subprocess.PIPE,先将标准输出输出到管道上,然后在通过read()输出到屏幕上;PIPE相当于一个存储功能,屏幕不能保存结果,结果保存在PIPE中,PIPE在内存中;这种方法可以隔离错误信息;输入时也是一样,不同进程之间相互通信,要通过管道来进行;
>>> subprocess.run(["ls", "-l"]) # doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)
>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1
>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')
调用subprocess.run(...)是推荐的常用方法,但是run()方法在python3.5才出现的方法,在大多数情况下能满足需求,但如果你可能需要进行一些复杂的与系统的交互的话,你还可以用subprocess.Popen(),语法如下:
p = subprocess.Popen("find / -size +1000000 -exec ls -shl {} \;",shell=True,stdout=subprocess.PIPE)
print(p.stdout.read())
可用参数:
- args:shell命令,可以是字符串或者序列类型(如:list,元组)
- bufsize:指定缓冲。0 无缓冲,1 行缓冲,其他 缓冲区大小,负值 系统缓冲
- stdin, stdout, stderr:分别表示程序的标准输入、输出、错误句柄
- preexec_fn:只在Unix平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用
- close_sfs:在windows平台下,如果close_fds被设置为True,则新创建的子进程将不会继承父进程的输入、输出、错误管道。所以不能将close_fds设置为True同时重定向子进程的标准输入、输出与错误(stdin, stdout, stderr)。
- shell:不要python解析命令,直接传递到系统上让系统来解析;
- cwd:用于设置子进程的当前目录,
- env:用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父进程中继承。
- universal_newlines:不同系统的换行符不同,True -> 同意使用 \n,默认自动兼容windows和linux
- startupinfo与createionflags只在windows下有效,将被传递给底层的CreateProcess()函数,用于设置子进程的一些属性,如:主窗口的外观,进程的优先级等等
终端输入的命令分为两种:
- 输入即可得到输出,如:ifconfig
- 输入进行某环境,依赖再输入,如:python
需要交互的命令示例
import subprocess
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
obj.stdin.write('print 1 \n ')
obj.stdin.write('print 2 \n ')
obj.stdin.write('print 3 \n ')
obj.stdin.write('print 4 \n ')
out_error_list = obj.communicate(timeout=10)
print out_error_list
subprocess实现sudo 自动输入密码(可以不用这个函数的方法,直接echo即可)
import subprocess
def mypass():
mypass = '123' #or get the password from anywhere
return mypass
echo = subprocess.Popen(['echo',mypass()],
stdout=subprocess.PIPE,
)
sudo = subprocess.Popen(['sudo','-S','iptables','-L'],
stdin=echo.stdout,
stdout=subprocess.PIPE,
)
end_of_pipe = sudo.stdout
print "Password ok \n Iptables Chains %s" % end_of_pipe.read()
使用linux的命令:
echo 'password' | sudo -S iptables -L
另外Python2.7中,Commands 模块(windows上不好用),commands.getstatusoutput()
>>> commands.getstatusoutput('pwd')
(0, '/Users/chenzhuanglan')
此命令在Python3中可以通过subprocess.getstatusoutput()方法代替
>>> subprocess.getstatusoutput('ls')
(0, 'Applications\nApplications (Parallels)\nDesktop\nDocuments\nDownloads\nDropbox\nLibrary\nMovies\nMusic\nMusic-local\nOneDrive\nParallels\nPictures\nPublic\nlearning\nprivate\nworking\n铃声\n虚拟机')
>>>
十五、logging 模块
logging的日志可以分为 debug(), info(), warning(), error() and critical() 5个级别
把日志写到文件中
import logging
logging.basicConfig(filename='example.log',level=logging.INFO)
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')
其中下面这句中的level=loggin.INFO意思是,把日志纪录级别设置为INFO,也就是说,只有当日志是INFO或比INFO级别更高的日志才会被纪录到文件里,在这个例子, 第一条日志是不会被纪录的,如果希望纪录debug的日志,那把日志级别改成DEBUG就行了。
logging.basicConfig(filename='example.log',level=logging.INFO)
感觉上面的日志格式忘记加上时间啦,日志不知道时间怎么行呢,下面就来加上!
import logging
logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
logging.warning('is when this event was logged.')
#输出
12/12/2010 11:46:36 AM is when this event was logged.

Python 使用logging模块记录日志涉及四个主要类,使用官方文档中的概括最为合适:
logger提供了应用程序可以直接使用的接口;
handler将(logger创建的)日志记录发送到合适的目的输出;
filter提供了细度设备来决定输出哪条日志记录;
formatter决定日志记录的最终输出格式。
logger
每个程序在输出信息之前都要获得一个Logger。Logger通常对应了程序的模块名,比如聊天工具的图形界面模块可以这样获得它的Logger:
LOG=logging.getLogger(”chat.gui”)
而核心模块可以这样:
LOG=logging.getLogger(”chat.kernel”)
Logger.setLevel(lel):指定最低的日志级别,低于lel的级别将被忽略。debug是最低的内置级别,critical为最高
Logger.addFilter(filt)、Logger.removeFilter(filt):添加或删除指定的filter
Logger.addHandler(hdlr)、Logger.removeHandler(hdlr):增加或删除指定的handler
Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():可以设置的日志级别
handler
handler对象负责发送相关的信息到指定目的地。Python的日志系统有多种Handler可以使用。有些Handler可以把信息输出到控制台,有些Logger可以把信息输出到文件,还有些 Handler可以把信息发送到网络上。如果觉得不够用,还可以编写自己的Handler。可以通过addHandler()方法添加多个多handler
Handler.setLevel(lel):指定被处理的信息级别,低于lel级别的信息将被忽略
Handler.setFormatter():给这个handler选择一个格式
Handler.addFilter(filt)、Handler.removeFilter(filt):新增或删除一个filter对象
每个Logger可以附加多个Handler。接下来我们就来介绍一些常用的Handler:
-
logging.StreamHandler(屏幕输出)
使用这个Handler可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息。它的构造函数是:
StreamHandler([strm])
其中strm参数是一个文件对象。默认是sys.stderr -
logging.FileHandler(文件输出)
和StreamHandler类似,用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件。它的构造函数是:
FileHandler(filename[,mode])
filename是文件名,必须指定一个文件名。
mode是文件的打开方式。参见Python内置函数open()的用法。默认是’a',即添加到文件末尾。 -
logging.handlers.RotatingFileHandler(日志文件大小滚动方式)
这个Handler类似于上面的FileHandler,但是它可以管理文件大小。当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建 一个新的同名日志文件继续输出。比如日志文件是chat.log。当chat.log达到指定的大小之后,RotatingFileHandler自动把 文件改名为chat.log.1。不过,如果chat.log.1已经存在,会先把chat.log.1重命名为chat.log.2。。。最后重新创建 chat.log,继续输出日志信息。它的构造函数是:
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
其中filename和mode两个参数和FileHandler一样。
maxBytes用于指定日志文件的最大文件大小。如果maxBytes为0,意味着日志文件可以无限大,这时上面描述的重命名过程就不会发生。
backupCount用于指定保留的备份文件的个数。比如,如果指定为2,当上面描述的重命名过程发生时,原有的chat.log.2并不会被更名,而是被删除。 -
logging.handlers.TimedRotatingFileHandler (日志文件时间滚动方式)
这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就 自动创建新的日志文件。重命名的过程与RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。它的构造函数是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。
interval是时间间隔。
when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:
S 秒
M 分
H 小时
D 天
W 每星期(interval==0时代表星期一)
midnight 每天凌晨
import logging
# create logger
logger = logging.getLogger('TEST-LOG') #自定义名字
logger.setLevel(logging.DEBUG) #最低等级是DEBUG
# create console handler and set level to debug
ch = logging.StreamHandler() #屏幕的handler
ch.setLevel(logging.WARNING) #设置hanlder的日志级别
# create file handler and set level to warning
fh = logging.FileHandler("access.log",encoding='utf-8')
fh.setLevel(logging.ERROR)
# create formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
#设置不同的handler的输出格式
# fh_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# fh.setFormatter(fh_formatter)
# add formatter to ch and fh
ch.setFormatter(formatter)
fh.setFormatter(formatter)
# add ch and fh to logger
logger.addHandler(ch)
logger.addHandler(fh)
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')
十六、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'
'(?P<name>...)' 分组匹配 re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","371481199306143242").groupdict("city") 结果{'province': '3714', 'city': '81', 'birthday': '1993'}
最常用的匹配语法
re.match 从头开始匹配
re.search 匹配包含
re.findall 把所有匹配到的字符放到以列表中的元素返回
re.splitall 以匹配到的字符当做列表分隔符
re.sub 匹配字符并替换
反斜杠的困扰
与大多数编程语言相同,正则表达式里使用""作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符"",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\":前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。Python里的原生字符串很好地解决了这个问题,这个例子中的正则表达式可以使用r"\"表示。同样,匹配一个数字的"\d"可以写成r"\d"。有了原生字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。
仅需轻轻知道的几个匹配模式
re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
M(MULTILINE): 多行模式,改变'^'和'$'的行为(参见上图)
S(DOTALL): 点任意匹配模式,改变'.'的行为
例如:
#!/usr/bin/python
import re
line = "Cats are smarter than dogs";
matchObj = re.match( r'dogs', line, re.M|re.I)
if matchObj:
print "match --> matchObj.group() : ", matchObj.group()
else:
print "No match!!"
matchObj = re.search( r'dogs', line, re.M|re.I)
if matchObj:
print "search --> matchObj.group() : ", matchObj.group()
else:
print "No match!!"
执行结果:
No match!!
search --> matchObj.group() : dogs
十七、uuid模块
uuid.uuid1() 设备唯一标识符,基于设备MAC、时间等参数
十八、动态导入模块
lib = __import__('lib.aa')
# 看上去导入的是lib.aa,实际上此时导入的是lib,但是如果不写'lib.aa'而只写'lib'的话,则aa这个模块不能导入,使用递归的方法是找不到的;
print(lib)
obj = lib.aa.C() #要调用C这个类,只能这样调用;若在import时,写的是'lib',那么此时就会报错。
上面的方法是解释器自己用的,不建议使用
官方建议使用的方法:
import importlib
aa = importlib.import_module('lib.aa') #此处是直接导入了aa模块,在调用时直接使用aa即可;
print(aa)
obj = aa.C() #不用写'lib.aa.C()'


浙公网安备 33010602011771号