OS 模块

os 常用方法
os.remove(‘path/filename’) 删除文件
os.rename(oldname, newname) 重命名文件
os.walk() 生成目录树下的所有文件名
os.chdir(\'dirname\') 改变目录
os.mkdir/makedirs(\'dirname\')创建目录/多层目录
os.rmdir/removedirs(\'dirname\') 删除目录/多层目录
os.listdir(\'dirname\') 列出指定目录的文件
os.getcwd() 取得当前工作目录
os.chmod() 改变目录权限
os.path. name(‘path/filename’) 去掉目录路径,返回文件名
os.path.dirname(‘path/filename’) 去掉文件名,返回目录路径
os.path.join(path1[,path2[,...]]) 将分离的各部分组合成一个路径名
os.path.split(\'path\') 返回( dirname(), name())元组
os.path.splitext() 返回 (filename, extension) 元组
os.path.getatime\\ctime\\mtime 分别返回最近访问、创建、修改时间
os.path.getsize() 返回文件大小
os.path.exists() 是否存在
os.path.isabs() 是否为绝对路径
os.path.isdir() 是否为目录
os.path.isfile() 是否为文件

os模块就是对操作系统进行操作,使用该模块必须先导入模块:
import os

#getcwd() 获取当前工作目录(当前工作目录默认都是当前文件所在的文件夹)
result = os.getcwd()
print(result)

#chdir()改变当前工作目录
os.chdir(\'/home/sy\')
result = os.getcwd()
print(result)

open(\'02.txt\',\'w\')

#操作时如果书写完整的路径则不需要考虑默认工作目录的问题,按照实际书写路径操作
open(\'/home/sy/下载/02.txt\',\'w\')

#listdir() 获取指定文件夹中所有内容的名称列表
result = os.listdir(\'/home/sy\')
print(result)

#mkdir()  创建文件夹
#os.mkdir(\'girls\')
#os.mkdir(\'boys\',0o777)

#makedirs()  递归创建文件夹
#os.makedirs(\'/home/sy/a/b/c/d\')

#rmdir() 删除空目录
#os.rmdir(\'girls\')

#removedirs 递归删除文件夹  必须都是空目录
#os.removedirs(\'/home/sy/a/b/c/d\')

#rename() 文件或文件夹重命名
#os.rename(\'/home/sy/a\',\'/home/sy/alibaba\'
#os.rename(\'02.txt\',\'002.txt\')

#stat() 获取文件或者文件夹的信息
#result = os.stat(\'/home/sy/PycharmProject/Python3/10.27/01.py)
#print(result)

#system() 执行系统命令(危险函数)
#result = os.system(\'ls -al\')  #获取隐藏文件
#print(result)

#环境变量
\'\'\'
环境变量就是一些命令的集合
操作系统的环境变量就是操作系统在执行系统命令时搜索命令的目录的集合
\'\'\'
#getenv() 获取系统的环境变量
result = os.getenv(\'PATH\')
print(result.split(\':\'))

#putenv() 将一个目录添加到环境变量中(临时增加仅对当前脚本有效)
#os.putenv(\'PATH\',\'/home/sy/下载\')
#os.system(\'syls\')

#exit() 退出终端的命令

#os模块中的常用值
#curdir  表示当前文件夹   .表示当前文件夹  一般情况下可以省略
print(os.curdir)

#pardir  表示上一层文件夹   ..表示上一层文件夹  不可省略!
print(os.pardir)

#os.mkdir(\'../../../man\')#相对路径  从当前目录开始查找
#os.mkdir(\'/home/sy/man1\')#绝对路径  从根目录开始查找

#name 获取代表操作系统的名称字符串
print(os.name) #posix -> linux或者unix系统  nt -> window系统

#sep 获取系统路径间隔符号  window ->\\    linux ->/
print(os.sep)

#extsep 获取文件名称和后缀之间的间隔符号  window & linux -> .
print(os.extsep)

#linesep  获取操作系统的换行符号  window -> \\r\\n  linux/unix -> \\n
print(repr(os.linesep))



#导入os模块
import os

#以下内容都是os.path子模块中的内容

#abspath()  将相对路径转化为绝对路径
path = \'./boys\'#相对
result = os.path.abspath(path)
print(result)

#dirname()  获取完整路径当中的目录部分  &   name()获取完整路径当中的主体部分
path = \'/home/sy/boys\'
result = os.path.dirname(path)
print(result)

result = os.path. name(path)
print(result)

#split() 将一个完整的路径切割成目录部分和主体部分
path = \'/home/sy/boys\'
result = os.path.split(path)
print(result)

#join() 将2个路径合并成一个
var1 = \'/home/sy\'
var2 = \'000.py\'
result = os.path.join(var1,var2)
print(result)

#splitext() 将一个路径切割成文件后缀和其他两个部分,主要用于获取文件的后缀
path = \'/home/sy/000.py\'
result = os.path.splitext(path)
print(result)

#getsize()  获取文件的大小
#path = \'/home/sy/000.py\'
#result = os.path.getsize(path)
#print(result)

#isfile() 检测是否是文件
path = \'/home/sy/000.py\'
result = os.path.isfile(path)
print(result)

#isdir()  检测是否是文件夹
result = os.path.isdir(path)
print(result)

#is () 检测是否是链接
path = \'/initrd.img.old\'
result = os.path.is (path)
print(result)

#getctime() 获取文件的创建时间 get create time
#getmtime() 获取文件的修改时间 get modify time
#getatime() 获取文件的访问时间 get active time

import time

filepath = \'/home/sy/下载/chls\'

result = os.path.getctime(filepath)
print(time.ctime(result))

result = os.path.getmtime(filepath)
print(time.ctime(result))

result = os.path.getatime(filepath)
print(time.ctime(result))

#exists() 检测某个路径是否真实存在
filepath = \'/home/sy/下载/chls\'
result = os.path.exists(filepath)
print(result)

#isabs() 检测一个路径是否是绝对路径
path = \'/boys\'
result = os.path.isabs(path)
print(result)

#samefile() 检测2个路径是否是同一个文件
path1 = \'/home/sy/下载/001\'
path2 = \'../../../下载/001\'
result = os.path.samefile(path1,path2)
print(result)


#os.environ 用于获取和设置系统环境变量的内置值
import os
#获取系统环境变量  getenv() 效果
print(os.environ[\'PATH\'])

#设置系统环境变量 putenv()
os.environ[\'PATH\'] += \':/home/sy/下载\'
os.system(\'chls\')

 sys 模块

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.maxint 最大的Int值
sys.maxunicode 最大的Unicode值
sys.modules 返回系统导入的模块字段,key是模块名,value是模块
sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform 返回操作系统平台名称
sys.stdout 标准输出
sys.stdin 标准输入
sys.stderr 错误输出
sys.exc_clear() 用来清除当前线程所出现的当前的或最近的错误信息
sys.exec_prefix 返回平台独立的python文件安装的位置
sys.byteorder 本地字节规则的指示器,big-endian平台的值是\'big\',little-endian平台的值是\'little\'
sys.copyright 记录python版权相关的东西
sys.api_version 解释器的C的API版本

time模块

time模块中时间表现的格式主要有三种:
  a、timestamp时间戳,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量
  b、struct_time时间元组,共有九个元素组。
  c、format time 格式化时间,已格式化的结构使时间更具可读性。包括自定义格式和固定格式。

主要time生成方法和time格式转换方法实例:

#! /usr/bin/env python
# -*- coding:utf-8 -*-

import time

# 生成timestamp
time.time()
# 1477471508.05
#struct_time to timestamp
time.mktime(time.localtime())
#生成struct_time
# timestamp to struct_time 本地时间
time.localtime()
time.localtime(time.time())
# time.struct_time(tm_year=2016, tm_mon=10, tm_mday=26, tm_hour=16, tm_min=45, tm_sec=8, tm_wday=2, tm_yday=300, tm_isdst=0)

# timestamp to struct_time 格林威治时间
time.gmtime()
time.gmtime(time.time())
# time.struct_time(tm_year=2016, tm_mon=10, tm_mday=26, tm_hour=8, tm_min=45, tm_sec=8, tm_wday=2, tm_yday=300, tm_isdst=0)

#format_time to struct_time
time.strptime(\'2011-05-05 16:37:06\', \'%Y-%m-%d %X\')
# time.struct_time(tm_year=2011, tm_mon=5, tm_mday=5, tm_hour=16, tm_min=37, tm_sec=6, tm_wday=3, tm_yday=125, tm_isdst=-1)

#生成format_time
#struct_time to format_time
time.strftime(\"%Y-%m-%d %X\")
time.strftime(\"%Y-%m-%d %X\",time.localtime())
# 2016-10-26 16:48:41


#生成固定格式的时间表示格式
time.asctime(time.localtime())
time.ctime(time.time())
# Wed Oct 26 16:45:08 2016

datetime模块

datatime模块重新封装了time模块,提供更多接口,提供的类有:date,time,datetime,timedelta,tzinfo。

1、date类

datetime.date(year, month, day)

静态方法和字段

date.max、date.min:date对象所能表示的最大、最小日期;
date.resolution:date对象表示日期的最小单位。这里是天。
date.today():返回一个表示当前本地日期的date对象;
date.fromtimestamp(timestamp):根据给定的时间戮,返回一个date对象;
d1 = date(2011,06,03)#date对象
d1.year、date.month、date.day:年、月、日;
d1.replace(year, month, day):生成一个新的日期对象,用参数指定的年,月,日代替原有对象中的属性。(原有对象仍保持不变)
d1.timetuple():返回日期对应的time.struct_time对象;
d1.weekday():返回weekday,如果是星期一,返回0;如果是星期2,返回1,以此类推;
d1.isoweekday():返回weekday,如果是星期一,返回1;如果是星期2,返回2,以此类推;
d1.isocalendar():返回格式如(year,month,day)的元组;
d1.isoformat():返回格式如\'YYYY-MM-DD’的字符串;
d1.strftime(fmt):和time模块format相同。

 

2、time类

datetime.time(hour[ , minute[ , second[ , microsecond[ , tzinfo] ] ] ] ) 

静态方法和字段

time.min、time.max:time类所能表示的最小、最大时间。其中,time.min = time(0, 0, 0, 0), time.max = time(23, 59, 59, 999999);
time.resolution:时间的最小单位,这里是1微秒;
t1 = datetime.time(10,23,15)#time对象
t1.hour、t1.minute、t1.second、t1.microsecond:时、分、秒、微秒;
t1.tzinfo:时区信息;
t1.replace([ hour[ , minute[ , second[ , microsecond[ , tzinfo] ] ] ] ] ):创建一个新的时间对象,用参数指定的时、分、秒、微秒代替原有对象中的属性(原有对象仍保持不变);
t1.isoformat():返回型如\"HH:MM:SS\"格式的字符串表示;
t1.strftime(fmt):同time模块中的format;

3、datetime类

datetime相当于date和time结合起来。
datetime.datetime (year, month, day[ , hour[ , minute[ , second[ , microsecond[ , tzinfo] ] ] ] ] )

静态方法和字段

datetime.today():返回一个表示当前本地时间的datetime对象;
datetime.now([tz]):返回一个表示当前本地时间的datetime对象,如果提供了参数tz,则获取tz参数所指时区的本地时间;
datetime.utcnow():返回一个当前utc时间的datetime对象;#格林威治时间
datetime.fromtimestamp(timestamp[, tz]):根据时间戮创建一个datetime对象,参数tz指定时区信息;
datetime.utcfromtimestamp(timestamp):根据时间戮创建一个datetime对象;
datetime.combine(date, time):根据date和time,创建一个datetime对象;
datetime.strptime(date_string, format):将格式字符串转换为datetime对象;
dt=datetime.now()#datetime对象
dt.year、month、day、hour、minute、second、microsecond、tzinfo:
dt.date():获取date对象;
dt.time():获取time对象;
dt. replace ([ year[ , month[ , day[ , hour[ , minute[ , second[ , microsecond[ , tzinfo] ] ] ] ] ] ] ]):
dt. timetuple ()
dt. utctimetuple ()
dt. toordinal ()
dt. weekday ()
dt. isocalendar ()
dt. isoformat ([ sep] )
dt. ctime ():返回一个日期时间的C格式字符串,等效于time.ctime(time.mktime(dt.timetuple()));
dt. strftime (format)

4.timedelta类,时间加减

使用timedelta可以很方便的在日期上做天days,小时hour,分钟,秒,毫秒,微妙的时间计算,如果要计算月份则需要另外的办法。

#coding:utf-8
from  datetime import *

dt = datetime.now()
#日期减一天
dt1 = dt + timedelta(days=-1)#昨天
dt2 = dt - timedelta(days=1)#昨天
dt3 = dt + timedelta(days=1)#明天
delta_obj = dt3-dt
print type(delta_obj),delta_obj#<type \'datetime.timedelta\'> 1 day, 0:00:00
print delta_obj.days ,delta_obj.total_seconds()#1 86400.0

5、tzinfo时区类

#! /usr/bin/python
# coding=utf-8

from datetime import datetime, tzinfo,timedelta

\"\"\"
tzinfo是关于时区信息的类
tzinfo是一个抽象类,所以不能直接被实例化
\"\"\"
class UTC(tzinfo):
    \"\"\"UTC\"\"\"
    def __init__(self,offset = 0):
        self._offset = offset

    def utcoffset(self, dt):
        return timedelta(hours=self._offset)

    def tzname(self, dt):
        return \"UTC +%s\" % self._offset

    def dst(self, dt):
        return timedelta(hours=self._offset)

#北京时间
beijing = datetime(2011,11,11,0,0,0,tzinfo = UTC(8))
print \"beijing time:\",beijing
#曼谷时间
bangkok = datetime(2011,11,11,0,0,0,tzinfo = UTC(7))
print \"bangkok time\",bangkok
#北京时间转成曼谷时间
print \"beijing-time to bangkok-time:\",beijing.astimezone(UTC(7))

#计算时间差时也会考虑时区的问题
timespan = beijing - bangkok
print \"时差:\",timespan

#Output==================
# beijing time: 2011-11-11 00:00:00+08:00
# bangkok time 2011-11-11 00:00:00+07:00
# beijing-time to bangkok-time: 2011-11-10 23:00:00+07:00
# 时差: -1 day, 23:00:00

hashlib加密

hashlib主要提供字符加密功能,将md5和sha模块整合到了一起,支持md5,sha1, sha224, sha256, sha384, sha512等算法

具体应用

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#pyversion:python3.5
#owner:fuzj



import hashlib

# ######## md5 ########

string = \"beyongjie\"


md5 = hashlib.md5()
md5.update(string.encode(\'utf-8\'))     #注意转码
res = md5.hexdigest()
print(\"md5加密结果:\",res)

# ######## sha1 ########

sha1 = hashlib.sha1()
sha1.update(string.encode(\'utf-8\'))
res = sha1.hexdigest()
print(\"sha1加密结果:\",res)

# ######## sha256 ########

sha256 = hashlib.sha256()
sha256.update(string.encode(\'utf-8\'))
res = sha256.hexdigest()
print(\"sha256加密结果:\",res)


# ######## sha384 ########

sha384 = hashlib.sha384()
sha384.update(string.encode(\'utf-8\'))
res = sha384.hexdigest()
print(\"sha384加密结果:\",res)

# ######## sha512 ########

sha512= hashlib.sha512()
sha512.update(string.encode(\'utf-8\'))
res = sha512.hexdigest()
print(\"sha512加密结果:\",res)

输出结果:

md5加密结果: 0e725e477851ff4076f774dc312d4748 
sha1加密结果: 458d32be8ea38b66300174970ab0a8c0b734252f 
sha256加密结果: 1e62b55bfd02977943f885f6a0998af7cc9cfb95c8ac4a9f30ecccb7c05ec9f4 
sha384加密结果: e91cdf0d2570de5c96ee84e8a12cddf16508685e7a03b3e811099cfcd54b7f52183e20197cff7c07f312157f0ba4875b 
sha512加密结果: 3f0020a726e9c1cb5d22290c967f3dd1bcecb409a51a8088db520750c876aaec3f17a70d7981cd575ed4b89471f743f3f24a146a39d59f215ae3e208d0170073

 

注意:hashlib 加密啊的字符串类型为二进制编码,直接加密字符串会报如下错误:

sha1 = hashlib.sha1() 
sha1.update(string) 
res = sha1.hexdigest() 
print(\"sha1加密结果:\",res) 
TypeError: Unicode- s must be encoded before hashing

 

可以使用encode进行转换

shaa1 = hashlib.sha1()
shaa1.update(string.encode(\'utf-8\'))
res = shaa1.hexdigest()
print(\"sha1采用encode转换加密结果:\",res)

或者使用byte转换为二进制

shab1 = hashlib.sha1()
shab1.update(bytes(string,encoding=\'utf-8\'))
res = shab1.hexdigest()
print(\"sha1采用byte转换的结果:\",res)

以上输出:

sha1采用encode转换加密结果: 458d32be8ea38b66300174970ab0a8c0b734252f
sha1采用byte转换的结果: 458d32be8ea38b66300174970ab0a8c0b734252f

常用方法

  • hash.update(arg) 更新哈希对象以字符串参数, 注意:如果同一个hash对象重复调用该方法,则m.update(a); m.update(b) 等效于 m.update(a+b),看下面例子
m = hashlib.md5()
m.update(\'a\'.encode(\'utf-8\'))
res = m.hexdigest()
print(\"第一次a加密:\",res)

m.update(\'b\'.encode(\'utf-8\'))
res = m.hexdigest()
print(\"第二次b加密:\",res)


m1 = hashlib.md5()
m1.update(\'b\'.encode(\'utf-8\'))
res = m1.hexdigest()
print(\"b单独加密:\",res)

m2 = hashlib.md5()
m2.update(\'ab\'.encode(\'utf-8\'))
res = m2.hexdigest()
print(\"ab单独加密:\",res)
输出结果:
第一次a加密: 0cc175b9c0f1b6a831c399e269772661
第二次b加密: 187ef4436122d1cc2f40dc2b92f0eba0
b单独加密: 92eb5ffee6ae2fec3ad71c777531578f
ab单独加密: 187ef4436122d1cc2f40dc2b92f0eba0

hash.digest() 返回摘要,作为二进制数据字符串值,

hash.hexdigest() 返回摘要,作为十六进制数据字符串值,

hash.copy() 复制

高级加密

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

low = hashlib.md5()
low.update(\'ab\'.encode(\'utf-8\'))
res = low.hexdigest()
print(\"普通加密:\",res)

high = hashlib.md5(b\'beyondjie\')
high.update(\'ab\'.encode(\'utf-8\'))
res = high.hexdigest()
print(\"采用key加密:\",res)
输出结果:
普通加密: 187ef4436122d1cc2f40dc2b92f0eba0
采用key加密: 1b073f6b8cffe609751e4c98537b7653

附加HMAC-SHA1各语言版本实现

在各大开放平台大行其道的互联网开发潮流中,调用各平台的API接口过程中,无一例外都会用到计算签名值(sig值)。而在各种计算签名的方法中,经常被采用的就是HMAC-SHA1,现对HMAC-SHA1做一个简单的介绍: HMAC,散列消息鉴别码,基于密钥的Hash算法认证协议。实现原理为:利用已经公开的Hash函数和私有的密钥,来生成固定长度的消息鉴别码; SHA1、MD5等Hash算法是比较常用的不可逆Hash签名计算方法; 64,将任意序列的8字节字符转换为人眼无法直接识别的符号编码的一种方法;

import hmac
import hashlib
import  64

hmac.new(Token,data,hashlib.sha1).digest().encode(\' 64\').rstrip() 
Token:即接口的key data:要加密的数据 

logging模块简介

logging模块是Python内置的标准模块,主要用于输出运行日志,可以设置输出日志的等级、日志保存路径、日志文件回滚等;相比print,具备如下优点:

  1. 可以通过设置不同的日志等级,在release版本中只输出重要信息,而不必显示大量的调试信息;
  2. print将所有信息都输出到标准输出中,严重影响开发者从标准输出中查看其它数据;logging则可以由开发者决定将信息输出到什么地方,以及怎么输出;

logging模块使用

配置logging基本的设置,然后在控制台输出日志,

import logging
logging.basicConfig(level = logging.INFO,format = \'%(asctime)s - %(name)s - %(levelname)s - %(message)s\')
logger = logging.getLogger(__name__)

logger.info(\"Start print log\")
logger.debug(\"Do something\")
logger.warning(\"Something maybe fail.\")
logger.info(\"Finish\")

运行时,控制台输出,

2016-10-09 19:11:19,434 - __main__ - INFO - Start print log
2016-10-09 19:11:19,434 - __main__ - WARNING - Something maybe fail.
2016-10-09 19:11:19,434 - __main__ - INFO - Finish
logging中可以选择很多消息级别,如debug、info、warning、error以及critical。通过赋予logger或者handler不同的级别,开发者就可以只输出错误信息到特定的记录文件,或者在调试时只记录调试信息。

例如,我们将logger的级别改为DEBUG,再观察一下输出结果,

logging.basicConfig(level = logging.DEBUG,format = \'%(asctime)s - %(name)s - %(levelname)s - %(message)s\')
控制台输出,可以发现,输出了debug的信息。
2016-10-09 19:12:08,289 - __main__ - INFO - Start print log
2016-10-09 19:12:08,289 - __main__ - DEBUG - Do something
2016-10-09 19:12:08,289 - __main__ - WARNING - Something maybe fail.
2016-10-09 19:12:08,289 - __main__ - INFO - Finish
logging.basicConfig函数各参数:
filename:指定日志文件名;
filemode:和file函数意义相同,指定日志文件的打开模式,\'w\'或者\'a\';
format:指定输出的格式和内容,format可以输出很多有用的信息,
参数:作用

%(levelno)s:打印日志级别的数值
%(levelname)s:打印日志级别的名称
%(pathname)s:打印当前执行程序的路径,其实就是sys.argv[0]
%(filename)s:打印当前执行程序名
%(funcName)s:打印日志的当前函数
%(lineno)d:打印日志的当前行号
%(asctime)s:打印日志的时间
%(thread)d:打印线程ID
%(threadName)s:打印线程名称
%(process)d:打印进程ID
%(message)s:打印日志信息
datefmt:指定时间格式,同time.strftime();
level:设置日志级别,默认为logging.WARNNING;
stream:指定将日志的输出流,可以指定输出到sys.stderr,sys.stdout或者文件,默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略;

 将日志写入到文件

将日志写入到文件

设置logging,创建一个FileHandler,并对输出消息的格式进行设置,将其添加到logger,然后将日志写入到指定的文件中,

import logging
logger = logging.getLogger(__name__)
logger.setLevel(level = logging.INFO)
handler = logging.FileHandler(\"log.txt\")
handler.setLevel(logging.INFO)
formatter = logging.Formatter(\'%(asctime)s - %(name)s - %(levelname)s - %(message)s\')
handler.setFormatter(formatter)
logger.addHandler(handler)

logger.info(\"Start print log\")
logger.debug(\"Do something\")
logger.warning(\"Something maybe fail.\")
logger.info(\"Finish\")

log.txt中日志数据为,

2016-10-09 19:01:13,263 - __main__ - INFO - Start print log
2016-10-09 19:01:13,263 - __main__ - WARNING - Something maybe fail.
2016-10-09 19:01:13,263 - __main__ - INFO - Finish
将日志同时输出到屏幕和日志文件
logger中添加StreamHandler,可以将日志输出到屏幕上,
import logging
logger = logging.getLogger(__name__)
logger.setLevel(level = logging.INFO)
handler = logging.FileHandler(\"log.txt\")
handler.setLevel(logging.INFO)
formatter = logging.Formatter(\'%(asctime)s - %(name)s - %(levelname)s - %(message)s\')
handler.setFormatter(formatter)

console = logging.StreamHandler()
console.setLevel(logging.INFO)

logger.addHandler(handler)
logger.addHandler(console)

logger.info(\"Start print log\")
logger.debug(\"Do something\")
logger.warning(\"Something maybe fail.\")
logger.info(\"Finish\")

可以在log.txt文件和控制台中看到,

2016-10-09 19:20:46,553 - __main__ - INFO - Start print log
2016-10-09 19:20:46,553 - __main__ - WARNING - Something maybe fail.
2016-10-09 19:20:46,553 - __main__ - INFO - Finish
可以发现,logging有一个日志处理的主对象,其他处理方式都是通过addHandler添加进去,logging中包含的handler主要有如下几种,
handler名称:位置;作用

StreamHandler:logging.StreamHandler;日志输出到流,可以是sys.stderr,sys.stdout或者文件
FileHandler:logging.FileHandler;日志输出到文件
 RotatingHandler:logging.handlers. RotatingHandler;基本的日志回滚方式
RotatingHandler:logging.handlers.RotatingHandler;日志回滚方式,支持日志文件最大数量和日志文件回滚
TimeRotatingHandler:logging.handlers.TimeRotatingHandler;日志回滚方式,在一定时间区域内回滚日志文件
SocketHandler:logging.handlers.SocketHandler;远程输出日志到TCP/IP sockets
DatagramHandler:logging.handlers.DatagramHandler;远程输出日志到UDP sockets
SMTPHandler:logging.handlers.SMTPHandler;远程输出日志到邮件地址
SysLogHandler:logging.handlers.SysLogHandler;日志输出到syslog
NTEventLogHandler:logging.handlers.NTEventLogHandler;远程输出日志到Windows NT/2000/XP的事件日志
MemoryHandler:logging.handlers.MemoryHandler;日志输出到内存中的指定buffer
HTTPHandler:logging.handlers.HTTPHandler;通过\"GET\"或者\"POST\"远程输出到HTTP服务器
日志回滚
使用RotatingFileHandler,可以实现日志回滚,
import logging
from logging.handlers import RotatingFileHandler
logger = logging.getLogger(__name__)
logger.setLevel(level = logging.INFO)
#定义一个RotatingFileHandler,最多备份3个日志文件,每个日志文件最大1K
rHandler = RotatingFileHandler(\"log.txt\",maxBytes = 1*1024,backupCount = 3)
rHandler.setLevel(logging.INFO)
formatter = logging.Formatter(\'%(asctime)s - %(name)s - %(levelname)s - %(message)s\')
rHandler.setFormatter(formatter)

console = logging.StreamHandler()
console.setLevel(logging.INFO)
console.setFormatter(formatter)

logger.addHandler(rHandler)
logger.addHandler(console)

logger.info(\"Start print log\")
logger.debug(\"Do something\")
logger.warning(\"Something maybe fail.\")
logger.info(\"Finish\")

可以在工程目录中看到,备份的日志文件,

2016/10/09  19:36               732 log.txt
2016/10/09  19:36               967 log.txt.1
2016/10/09  19:36               985 log.txt.2
2016/10/09  19:36               976 log.txt.3

设置消息的等级

 可以设置不同的日志等级,用于控制日志的输出,

日志等级:使用范围

FATAL:致命错误
CRITICAL:特别糟糕的事情,如内存耗尽、磁盘空间为空,一般很少使用
ERROR:发生错误时,如IO操作失败或者连接问题
WARNING:发生很重要的事件,但是并不是错误时,如用户登录密码错误
INFO:处理请求或者状态变化等日常事务
DEBUG:调试过程中使用DEBUG等级,如算法中每个循环的中间状态

捕获traceback

Python中的traceback模块被用于跟踪异常返回信息,可以在logging中记录下traceback,

import logging
logger = logging.getLogger(__name__)
logger.setLevel(level = logging.INFO)
handler = logging.FileHandler(\"log.txt\")
handler.setLevel(logging.INFO)
formatter = logging.Formatter(\'%(asctime)s - %(name)s - %(levelname)s - %(message)s\')
handler.setFormatter(formatter)

console = logging.StreamHandler()
console.setLevel(logging.INFO)

logger.addHandler(handler)
logger.addHandler(console)

logger.info(\"Start print log\")
logger.debug(\"Do something\")
logger.warning(\"Something maybe fail.\")
try:
    open(\"sklearn.txt\",\"rb\")
except (SystemExit,KeyboardInterrupt):
    raise
except Exception:
    logger.error(\"Faild to open sklearn.txt from logger.error\",exc_info = True)

logger.info(\"Finish\")

控制台和日志文件log.txt中输出,

Start print log
Something maybe fail.
Faild to open sklearn.txt from logger.error
Traceback (most recent call last):
  File \"G:\\zhb7627\\Code\\Eclipse WorkSpace\\PythonTest\\test.py\", line 23, in <module>
    open(\"sklearn.txt\",\"rb\")
IOError: [Errno 2] No such file or directory: \'sklearn.txt\'
Finish
也可以使用logger.exception(msg,_args),它等价于logger.error(msg,exc_info = True,_args),
将
logger.error(\"Faild to open sklearn.txt from logger.error\",exc_info = True)
替换为,
logger.exception(\"Failed to open sklearn.txt from logger.exception\")
控制台和日志文件log.txt中输出,
Start print log
Something maybe fail.
Failed to open sklearn.txt from logger.exception
Traceback (most recent call last):
  File \"G:\\zhb7627\\Code\\Eclipse WorkSpace\\PythonTest\\test.py\", line 23, in <module>
    open(\"sklearn.txt\",\"rb\")
IOError: [Errno 2] No such file or directory: \'sklearn.txt\'
Finish

多模块使用logging

主模块mainModule.py,

import logging
import subModule
logger = logging.getLogger(\"mainModule\")
logger.setLevel(level = logging.INFO)
handler = logging.FileHandler(\"log.txt\")
handler.setLevel(logging.INFO)
formatter = logging.Formatter(\'%(asctime)s - %(name)s - %(levelname)s - %(message)s\')
handler.setFormatter(formatter)

console = logging.StreamHandler()
console.setLevel(logging.INFO)
console.setFormatter(formatter)

logger.addHandler(handler)
logger.addHandler(console)


logger.info(\"creating an instance of subModule.subModuleClass\")
a = subModule.SubModuleClass()
logger.info(\"calling subModule.subModuleClass.doSomething\")
a.doSomething()
logger.info(\"done with  subModule.subModuleClass.doSomething\")
logger.info(\"calling subModule.some_function\")
subModule.som_function()
logger.info(\"done with subModule.some_function\")

子模块subModule.py,

import logging
module_logger = logging.getLogger(\"mainModule.sub\")
class SubModuleClass( ):
    def __init__(self):
        self.logger = logging.getLogger(\"mainModule.sub.module\")
        self.logger.info(\"creating an instance in SubModuleClass\")
    def doSomething(self):
        self.logger.info(\"do something in SubModule\")
        a = []
        a.append(1)
        self.logger.debug(\"list a = \" + str(a))
        self.logger.info(\"finish something in SubModuleClass\")

def som_function():
    module_logger.info(\"call function some_function\")

执行之后,在控制和日志文件log.txt中输出,

2016-10-09 20:25:42,276 - mainModule - INFO - creating an instance of subModule.subModuleClass
2016-10-09 20:25:42,279 - mainModule.sub.module - INFO - creating an instance in SubModuleClass
2016-10-09 20:25:42,279 - mainModule - INFO - calling subModule.subModuleClass.doSomething
2016-10-09 20:25:42,279 - mainModule.sub.module - INFO - do something in SubModule
2016-10-09 20:25:42,279 - mainModule.sub.module - INFO - finish something in SubModuleClass
2016-10-09 20:25:42,279 - mainModule - INFO - done with  subModule.subModuleClass.doSomething
2016-10-09 20:25:42,279 - mainModule - INFO - calling subModule.some_function
2016-10-09 20:25:42,279 - mainModule.sub - INFO - call function some_function
2016-10-09 20:25:42,279 - mainModule - INFO - done with subModule.some_function
首先在主模块定义了logger\'mainModule\',并对它进行了配置,就可以在解释器进程里面的其他地方通过getLogger(\'mainModule\')得到的对象都是一样的,不需要重新配置,可以直接使用。定义的该logger的子logger,都可以共享父logger的定义和配置,所谓的父子logger是通过命名来识别,任意以\'mainModule\'开头的logger都是它的子logger,例如\'mainModule.sub\'。

实际开发一个application,首先可以通过logging配置文件编写好这个application所对应的配置,可以生成一个根logger,如\'PythonAPP\',然后在主函数中通过fileConfig加载logging配置,接着在application的其他地方、不同的模块中,可以使用根logger的子logger,如\'PythonAPP.Core\',\'PythonAPP.Web\'来进行log,而不需要反复的定义和配置各个模块的logger。

通过JSON或者YAML文件配置logging模块

尽管可以在Python代码中配置logging,但是这样并不够灵活,最好的方法是使用一个配置文件来配置。在Python 2.7及以后的版本中,可以从字典中加载logging配置,也就意味着可以通过JSON或者YAML文件加载日志的配置。

 通过JSON文件配置

JSON配置文件,

{
    \"version\":1,
    \"disable_existing_loggers\":false,
    \"formatters\":{
        \"simple\":{
            \"format\":\"%(asctime)s - %(name)s - %(levelname)s - %(message)s\"
        }
    },
    \"handlers\":{
        \"console\":{
            \"class\":\"logging.StreamHandler\",
            \"level\":\"DEBUG\",
            \"formatter\":\"simple\",
            \"stream\":\"ext://sys.stdout\"
        },
        \"info_file_handler\":{
            \"class\":\"logging.handlers.RotatingFileHandler\",
            \"level\":\"INFO\",
            \"formatter\":\"simple\",
            \"filename\":\"info.log\",
            \"maxBytes\":\"10485760\",
            \"backupCount\":20,
            \"encoding\":\"utf8\"
        },
        \"error_file_handler\":{
            \"class\":\"logging.handlers.RotatingFileHandler\",
            \"level\":\"ERROR\",
            \"formatter\":\"simple\",
            \"filename\":\"errors.log\",
            \"maxBytes\":10485760,
            \"backupCount\":20,
            \"encoding\":\"utf8\"
        }
    },
    \"loggers\":{
        \"my_module\":{
            \"level\":\"ERROR\",
            \"handlers\":[\"info_file_handler\"],
            \"propagate\":\"no\"
        }
    },
    \"root\":{
        \"level\":\"INFO\",
        \"handlers\":[\"console\",\"info_file_handler\",\"error_file_handler\"]
    }
}
通过JSON加载配置文件,然后通过logging.dictConfig配置logging,
import json
import logging.config
import os

def setup_logging(default_path = \"logging.json\",default_level = logging.INFO,env_key = \"LOG_CFG\"):
    path = default_path
    value = os.getenv(env_key,None)
    if value:
        path = value
    if os.path.exists(path):
        with open(path,\"r\") as f:
            config = json.load(f)
            logging.config.dictConfig(config)
    else:
        logging.basicConfig(level = default_level)

def func():
    logging.info(\"start func\")

    logging.info(\"exec func\")

    logging.info(\"end func\")

if __name__ == \"__main__\":
    setup_logging(default_path = \"logging.json\")
    func()

 

通过YAML文件配置

通过YAML文件进行配置,比JSON看起来更加简介明了,

version: 1
disable_existing_loggers: False
formatters:
        simple:
            format: \"%(asctime)s - %(name)s - %(levelname)s - %(message)s\"
handlers:
    console:
            class: logging.StreamHandler
            level: DEBUG
            formatter: simple
            stream: ext://sys.stdout
    info_file_handler:
            class: logging.handlers.RotatingFileHandler
            level: INFO
            formatter: simple
            filename: info.log
            maxBytes: 10485760
            backupCount: 20
            encoding: utf8
    error_file_handler:
            class: logging.handlers.RotatingFileHandler
            level: ERROR
            formatter: simple
            filename: errors.log
            maxBytes: 10485760
            backupCount: 20
            encoding: utf8
loggers:
    my_module:
            level: ERROR
            handlers: [info_file_handler]
            propagate: no
root:
    level: INFO
    handlers: [console,info_file_handler,error_file_handler]
通过YAML加载配置文件,然后通过logging.dictConfig配置logging,
import yaml
import logging.config
import os

def setup_logging(default_path = \"logging.yaml\",default_level = logging.INFO,env_key = \"LOG_CFG\"):
    path = default_path
    value = os.getenv(env_key,None)
    if value:
        path = value
    if os.path.exists(path):
        with open(path,\"r\") as f:
            config = yaml.load(f)
            logging.config.dictConfig(config)
    else:
        logging.basicConfig(level = default_level)

def func():
    logging.info(\"start func\")

    logging.info(\"exec func\")

    logging.info(\"end func\")

if __name__ == \"__main__\":
    setup_logging(default_path = \"logging.yaml\")
    func()

 

subprocess模块

subprocess是Python 2.4中新增的一个模块,它允许你生成新的进程,连接到它们的 input/output/error 管道,并获取它们的返回(状态)码。这个模块的目的在于替换几个旧的模块和方法,如:

  • os.system
  • os.spawn*

1. subprocess模块中的常用函数

函数 描述
subprocess.run() Python 3.5中新增的函数。执行指定的命令,等待命令执行完成后返回一个包含执行结果的CompletedProcess类的实例。
subprocess.call() 执行指定的命令,返回命令执行状态,其功能类似于os.system(cmd)。
subprocess.check_call() Python 2.5中新增的函数。 执行指定的命令,如果执行成功则返回状态码,否则抛出异常。其功能等价于subprocess.run(..., check=True)。
subprocess.check_output() Python 2.7中新增的的函数。执行指定的命令,如果执行状态码为0则返回命令执行结果,否则抛出异常。
subprocess.getoutput(cmd) 接收字符串格式的命令,执行命令并返回执行结果,其功能类似于os.popen(cmd).read()和commands.getoutput(cmd)。
subprocess.getstatusoutput(cmd) 执行cmd命令,返回一个元组(命令执行状态, 命令执行结果输出),其功能类似于commands.getstatusoutput()。

说明:

  1. 在Python 3.5之后的版本中,官方文档中提倡通过subprocess.run()函数替代其他函数来使用subproccess模块的功能;
  2. 在Python 3.5之前的版本中,我们可以通过subprocess.call(),subprocess.getoutput()等上面列出的其他函数来使用subprocess模块的功能;
  3. subprocess.run()、subprocess.call()、subprocess.check_call()和subprocess.check_output()都是通过对subprocess.Popen的封装来实现的高级函数,因此如果我们需要更复杂功能时,可以通过subprocess.Popen来完成。
  4. subprocess.getoutput()和subprocess.getstatusoutput()函数是来自Python 2.x的commands模块的两个遗留函数。它们隐式的调用系统shell,并且不保证其他函数所具有的安全性和异常处理的一致性。另外,它们从Python 3.3.4开始才支持Windows平台。

2. 上面各函数的定义及参数说明

函数参数列表:

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False, universal_newlines=False)

subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)

subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)

subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False, timeout=None)

subprocess.getstatusoutput(cmd)

subprocess.getoutput(cmd)
参数说明:
  • args: 要执行的shell命令,默认应该是一个字符串序列,如[\'df\', \'-Th\']或(\'df\', \'-Th\'),也可以是一个字符串,如\'df -Th\',但是此时需要把shell参数的值置为True。
  • shell: 如果shell为True,那么指定的命令将通过shell执行。如果我们需要访问某些shell的特性,如管道、文件名通配符、环境变量扩展功能,这将是非常有用的。当然,python本身也提供了许多类似shell的特性的实现,如glob、fnmatch、os.walk()、os.path.expandvars()、os.expanduser()和shutil等。
  • check: 如果check参数的值是True,且执行命令的进程以非0状态码退出,则会抛出一个CalledProcessError的异常,且该异常对象会包含 参数、退出状态码、以及stdout和stderr(如果它们有被捕获的话)。
  • stdout, stderr:
  • run()函数默认不会捕获命令执行结果的正常输出和错误输出,如果我们向获取这些内容需要传递subprocess.PIPE,然后可以通过返回的CompletedProcess类实例的stdout和stderr属性或捕获相应的内容;
  • call()和check_call()函数返回的是命令执行的状态码,而不是CompletedProcess类实例,所以对于它们而言,stdout和stderr不适合赋值为subprocess.PIPE;
  • check_output()函数默认就会返回命令执行结果,所以不用设置stdout的值,如果我们希望在结果中捕获错误信息,可以执行stderr=subprocess.STDOUT。
  • input: 该参数是传递给Popen.communicate(),通常该参数的值必须是一个字节序列,如果universal_newlines=True,则其值应该是一个字符串。
  • universal_newlines: 该参数影响的是输入与输出的数据格式,比如它的值默认为False,此时stdout和stderr的输出是字节序列;当该参数的值设置为True时,stdout和stderr的输出是字符串。

3. subprocess.CompletedProcess类介绍

需要说明的是,subprocess.run()函数是Python3.5中新增的一个高级函数,其返回值是一个subprocess.CompletedPorcess类的实例,因此,subprocess.completedPorcess类也是Python 3.5中才存在的。它表示的是一个已结束进程的状态信息,它所包含的属性如下:

  • args: 用于加载该进程的参数,这可能是一个列表或一个字符串
  • returncode: 子进程的退出状态码。通常情况下,退出状态码为0则表示进程成功运行了;一个负值-N表示这个子进程被信号N终止了
  • stdout: 从子进程捕获的stdout。这通常是一个字节序列,如果run()函数被调用时指定universal_newlines=True,则该属性值是一个字符串。如果run()函数被调用时指定stderr=subprocess.STDOUT,那么stdout和stderr将会被整合到这一个属性中,且stderr将会为None
  • stderr: 从子进程捕获的stderr。它的值与stdout一样,是一个字节序列或一个字符串。如果stderr灭有被捕获的话,它的值就为None
  • check_returncode(): 如果returncode是一个非0值,则该方法会抛出一个CalledProcessError异常。

4. 实例

subprocess.run()

>>> 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.call()
>>> subprocess.call([\'ls\',  \'-l\'])
总用量 160
drwxr-xr-x  2 wader wader   4096 12月  7  2015 公共的
drwxr-xr-x  2 wader wader   4096 12月  7  2015 模板
drwxr-xr-x  2 wader wader   4096 12月  7  2015 视频
drwxr-xr-x  2 wader wader   4096 12月  7  2015 图片
drwxr-xr-x  2 wader wader   4096 12月  7  2015 文档
drwxr-xr-x  2 wader wader   4096  4月 13  2016 下载
drwxr-xr-x  2 wader wader   4096 12月  7  2015 音乐
drwxr-xr-x  7 wader wader   4096  5月 26  2016 桌面
0
>>> subprocess.call(\'ls -l\', shell=True)
总用量 160
drwxr-xr-x  2 wader wader   4096 12月  7  2015 公共的
drwxr-xr-x  2 wader wader   4096 12月  7  2015 模板
drwxr-xr-x  2 wader wader   4096 12月  7  2015 视频
drwxr-xr-x  2 wader wader   4096 12月  7  2015 图片
drwxr-xr-x  2 wader wader   4096 12月  7  2015 文档
drwxr-xr-x  2 wader wader   4096  4月 13  2016 下载
drwxr-xr-x  2 wader wader   4096 12月  7  2015 音乐
drwxr-xr-x  7 wader wader   4096  5月 26  2016 桌面
0
>>> subprocess.call([\'ls\',  \'-l\'], stdout=subprocess.DEVNULL)
0
>>> subprocess.call([\'ls\',  \'-l\', \'/test\'])
ls: 无法访问/test: 没有那个文件或目录
2
suprocess.check_call()
>>> subprocess.check_call([\'ls\',  \'-l\'])
总用量 160
drwxr-xr-x  2 wader wader   4096 12月  7  2015 公共的
drwxr-xr-x  2 wader wader   4096 12月  7  2015 模板
drwxr-xr-x  2 wader wader   4096 12月  7  2015 视频
drwxr-xr-x  2 wader wader   4096 12月  7  2015 图片
drwxr-xr-x  2 wader wader   4096 12月  7  2015 文档
drwxr-xr-x  2 wader wader   4096  4月 13  2016 下载
drwxr-xr-x  2 wader wader   4096 12月  7  2015 音乐
drwxr-xr-x  7 wader wader   4096  5月 26  2016 桌面
0
>>> subprocess.check_call(\'ls -l\', shell=True)
总用量 160
drwxr-xr-x  2 wader wader   4096 12月  7  2015 公共的
drwxr-xr-x  2 wader wader   4096 12月  7  2015 模板
drwxr-xr-x  2 wader wader   4096 12月  7  2015 视频
drwxr-xr-x  2 wader wader   4096 12月  7  2015 图片
drwxr-xr-x  2 wader wader   4096 12月  7  2015 文档
drwxr-xr-x  2 wader wader   4096  4月 13  2016 下载
drwxr-xr-x  2 wader wader   4096 12月  7  2015 音乐
drwxr-xr-x  7 wader wader   4096  5月 26  2016 桌面
0
>>> subprocess.check_call(\'ls -l /test\', shell=True)
ls: 无法访问/test: 没有那个文件或目录
Traceback (most recent call last):
  File \"<stdin>\", line 1, in <module>
  File \"/usr/lib/python3.4/subprocess.py\", line 557, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command \'ls -l /test\' returned non-zero exit status 2
sbuprocess.check_output()
>>> ret = subprocess.check_output([\'ls\',  \'-l\'])
>>> print(ret)
b\' \\xe5\\x85\\xac\\xe5\\x85\\xb1\\xe7\\x9a\\x84\\ndrwxr-xr-x  2 wader wader   4096 12\\xe6\\x9c\\x88  7  2015 \\xe6\\xa8\\xa1\\xe6\\x9d\\xbf\\ndrwxr-xr-x  2 wader wader   4096 12\\xe6\\x9c\\x88  7  2015 \\xe8\\xa7\\x86\\xe9\\xa2\\x91\\ndrwxr-xr-x  2 wader wader   4096 12\\xe6\\x9c\\x88  7  2015 \\xe5\\x9b\\xbe\\xe7\\x89\\x87\\ndrwxr-xr-x  2 wader wader   4096 12\\xe6\\x9c\\x88  7  2015 \\xe6\\x96\\x87\\xe6\\xa1\\xa3\\ndrwxr-xr-x  2 wader wader   4096  4\\xe6\\x9c\\x88 13  2016 \\xe4\\xb8\\x8b\\xe8\\xbd\\xbd\\ndrwxr-xr-x  2 wader wader   4096 12\\xe6\\x9c\\x88  7  2015 \\xe9\\x9f\\xb3\\xe4\\xb9\\x90\\ndrwxr-xr-x  7 wader wader   4096  5\\xe6\\x9c\\x88 26  2016 \\xe6\\xa1\\x8c\\xe9\\x9d\\xa2\\n\'
>>> ret = subprocess.check_output([\'ls\',  \'-l\'], universal_newlines=True)
>>> print(ret)
总用量 160
drwxr-xr-x  2 wader wader   4096 12月  7  2015 公共的
drwxr-xr-x  2 wader wader   4096 12月  7  2015 模板
drwxr-xr-x  2 wader wader   4096 12月  7  2015 视频
drwxr-xr-x  2 wader wader   4096 12月  7  2015 图片
drwxr-xr-x  2 wader wader   4096 12月  7  2015 文档
drwxr-xr-x  2 wader wader   4096  4月 13  2016 下载
drwxr-xr-x  2 wader wader   4096 12月  7  2015 音乐
drwxr-xr-x  7 wader wader   4096  5月 26  2016 桌面
subprocess.getoutput()与subprocess.getstatusoutput()
>>> ret = subprocess.getoutput(\'ls -l\')
>>> print(ret)
总用量 160
drwxr-xr-x  2 wader wader   4096 12月  7  2015 公共的
drwxr-xr-x  2 wader wader   4096 12月  7  2015 模板
drwxr-xr-x  2 wader wader   4096 12月  7  2015 视频
drwxr-xr-x  2 wader wader   4096 12月  7  2015 图片
drwxr-xr-x  2 wader wader   4096 12月  7  2015 文档
drwxr-xr-x  2 wader wader   4096  4月 13  2016 下载
drwxr-xr-x  2 wader wader   4096 12月  7  2015 音乐
drwxr-xr-x  7 wader wader   4096  5月 26  2016 桌面
>>> retcode, output = subprocess.getstatusoutput(\'ls -l\')
>>> print(retcode)
0
>>> print(output)
总用量 160
drwxr-xr-x  2 wader wader   4096 12月  7  2015 公共的
drwxr-xr-x  2 wader wader   4096 12月  7  2015 模板
drwxr-xr-x  2 wader wader   4096 12月  7  2015 视频
drwxr-xr-x  2 wader wader   4096 12月  7  2015 图片
drwxr-xr-x  2 wader wader   4096 12月  7  2015 文档
drwxr-xr-x  2 wader wader   4096  4月 13  2016 下载
drwxr-xr-x  2 wader wader   4096 12月  7  2015 音乐
drwxr-xr-x  7 wader wader   4096  5月 26  2016 桌面
>>> retcode, output = subprocess.getstatusoutput(\'ls -l /test\')
>>> print(retcode)
2
>>> print(output)
ls: 无法访问/test: 没有那个文件或目录

三、subprocess.Popen介绍

该类用于在一个新的进程中执行一个子程序。前面我们提到过,上面介绍的这些函数都是基于subprocess.Popen类实现的,通过使用这些被封装后的高级函数可以很方面的完成一些常见的需求。由于subprocess模块底层的进程创建和管理是由Popen类来处理的,因此,当我们无法通过上面哪些高级函数来实现一些不太常见的功能时就可以通过subprocess.Popen类提供的灵活的api来完成。

1.subprocess.Popen的构造函数

class subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, 
    preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=False,
    startup_info=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=())
参数说明:
  • args: 要执行的shell命令,可以是字符串,也可以是命令各个参数组成的序列。当该参数的值是一个字符串时,该命令的解释过程是与平台相关的,因此通常建议将args参数作为一个序列传递。
  • bufsize: 指定缓存策略,0表示不缓冲,1表示行缓冲,其他大于1的数字表示缓冲区大小,负数 表示使用系统默认缓冲策略。
  • stdin, stdout, stderr: 分别表示程序标准输入、输出、错误句柄。
  • preexec_fn: 用于指定一个将在子进程运行之前被调用的可执行对象,只在Unix平台下有效。
  • close_fds: 如果该参数的值为True,则除了0,1和2之外的所有文件描述符都将会在子进程执行之前被关闭。
  • shell: 该参数用于标识是否使用shell作为要执行的程序,如果shell值为True,则建议将args参数作为一个字符串传递而不要作为一个序列传递。
  • cwd: 如果该参数值不是None,则该函数将会在执行这个子进程之前改变当前工作目录。
  • env: 用于指定子进程的环境变量,如果env=None,那么子进程的环境变量将从父进程中继承。如果env!=None,它的值必须是一个映射对象。
  • universal_newlines: 如果该参数值为True,则该文件对象的stdin,stdout和stderr将会作为文本流被打开,否则他们将会被作为二进制流被打开。
  • startupinfo和creationflags: 这两个参数只在Windows下有效,它们将被传递给底层的CreateProcess()函数,用于设置子进程的一些属性,如主窗口的外观,进程优先级等。

2. subprocess.Popen类的实例可调用的方法

方法 描述
Popen.poll() 用于检查子进程(命令)是否已经执行结束,没结束返回None,结束后返回状态码。
Popen.wait(timeout=None) 等待子进程结束,并返回状态码;如果在timeout指定的秒数之后进程还没有结束,将会抛出一个TimeoutExpired异常。
Popen.communicate(input=None, timeout=None) 该方法可用来与进程进行交互,比如发送数据到stdin,从stdout和stderr读取数据,直到到达文件末尾。
Popen.send_signal(signal) 发送指定的信号给这个子进程。
Popen.terminate() 停止该子进程。
Popen.kill() 杀死该子进程。

关于communicate()方法的说明:

  • 该方法中的可选参数 input 应该是将被发送给子进程的数据,或者如没有数据发送给子进程,该参数应该是None。input参数的数据类型必须是字节串,如果universal_newlines参数值为True,则input参数的数据类型必须是字符串。
  • 该方法返回一个元组(stdout_data, stderr_data),这些数据将会是字节穿或字符串(如果universal_newlines的值为True)。
  • 如果在timeout指定的秒数后该进程还没有结束,将会抛出一个TimeoutExpired异常。捕获这个异常,然后重新尝试通信不会丢失任何输出的数据。但是超时之后子进程并没有被杀死,为了合理的清除相应的内容,一个好的应用应该手动杀死这个子进程来结束通信。
  • 需要注意的是,这里读取的数据是缓冲在内存中的,所以,如果数据大小非常大或者是无限的,就不应该使用这个方法。

3. subprocess.Popen使用实例

实例1:
>>> import subprocess
>>>
>>> p = subprocess.Popen(\'df -Th\', stdout=subprocess.PIPE, shell=True)
>>> print(p.stdout.read())
Filesystem     Type      Size  Used Avail Use% Mounted on
/dev/vda1      ext4       40G   12G   26G  31% /
devtmpfs       devtmpfs  3.9G     0  3.9G   0% /dev
tmpfs          tmpfs     3.9G     0  3.9G   0% /dev/shm
tmpfs          tmpfs     3.9G  386M  3.5G  10% /run
tmpfs          tmpfs     3.9G     0  3.9G   0% /sys/fs/cgroup
tmpfs          tmpfs     783M     0  783M   0% /run/user/0
tmpfs          tmpfs     783M     0  783M   0% /run/user/1000
实例2:
>>> 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\')
>>> out,err = obj.communicate()
>>> print(out)
1
2
3

>>> print(err)
实例3:
>>> obj = subprocess.Popen([\"python\"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> out,err = obj.communicate(input=\'print(1) \\n\')
>>> print(out)
1

>>> print(err)
实例4:
实现类似df -Th | grep data命令的功能,实际上就是实现shell中管道的共功能。
>>> 
>>> p1 = subprocess.Popen([\'df\', \'-Th\'], stdout=subprocess.PIPE)
>>> p2 = subprocess.Popen([\'grep\', \'data\'], stdin=p1.stdout, stdout=subprocess.PIPE)
>>> out,err = p2.communicate()
>>> print(out)
/dev/vdb1      ext4      493G  4.8G  463G   2% /data
/dev/vdd1      ext4     1008G  420G  537G  44% /data1
/dev/vde1      ext4      985G  503G  432G  54% /data2

>>> print(err)
None

四、总结

那么我们到底该用哪个模块、哪个函数来执行命令与系统及系统进行交互呢?下面我们来做个总结:

  • 首先应该知道的是,Python2.4版本引入了subprocess模块用来替换os.system()、os.popen()、os.spawn*()等函数以及commands模块;也就是说如果你使用的是Python 2.4及以上的版本就应该使用subprocess模块了。
  • 如果你的应用使用的Python 2.4以上,但是是Python 3.5以下的版本,Python官方给出的建议是使用subprocess.call()函数。Python 2.5中新增了一个subprocess.check_call()函数,Python 2.7中新增了一个subprocess.check_output()函数,这两个函数也可以按照需求进行使用。
  • 如果你的应用使用的是Python 3.5及以上的版本(目前应该还很少),Python官方给出的建议是尽量使用subprocess.run()函数。
  • 当subprocess.call()、subprocess.check_call()、subprocess.check_output()和subprocess.run()这些高级函数无法满足需求时,我们可以使用subprocess.Popen类来实现我们需要的复杂功能。

json ,pickle模块

JSON(   Notation, JS 对象标记) 是一种轻量级的数据交换格式。JSON的数据格式其实就是python里面的字典格式,里面可以包含方括号括起来的数组,也就是python里面的列表。
在python中,有专门处理json格式的模块—— json 和 picle模块
      Json   模块提供了四个方法: dumps、dump、loads、load
    pickle 模块也提供了四个功能:dumps、dump、loads、load

一. dumps 和 dump:
 dumps和dump   序列化方法
       dumps只完成了序列化为str,
       dump必须传文件描述符,将序列化的str保存到文件中

查看源码:

def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
        allow_nan=True, cls=None, indent=None, separators=None,
        default=None, sort_keys=False, **kw):
    # Serialize ``obj`` to a JSON formatted ``str``.
    # 序列号 “obj” 数据类型 转换为 JSON格式的字符串 
def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
        allow_nan=True, cls=None, indent=None, separators=None,
        default=None, sort_keys=False, **kw):
    \"\"\"Serialize ``obj`` as a JSON formatted stream to ``fp`` (a
    ``.write()``-supporting file-like  ).
     我理解为两个动作,一个动作是将”obj“转换为JSON格式的字符串,还有一个动作是将字符串写入到文件中,也就是说文件描述符fp是必须要的参数 \"\"\"

示例代码:

>>> import json
>>> json.dumps([])    # dumps可以格式化所有的基本数据类型为字符串
\'[]\'
>>> json.dumps(1)    # 数字
\'1\'
>>> json.dumps(\'1\')   # 字符串
\'\"1\"\'
>>> dict = {\"name\":\"Tom\", \"age\":23}  
>>> json.dumps(dict)     # 字典
\'{\"name\": \"Tom\", \"age\": 23}\'
a = {\"name\":\"Tom\", \"age\":23}
with open(\"test.json\", \"w\", encoding=\'utf-8\') as f:
    # indent 超级好用,格式化保存字典,默认为None,小于0为零个空格
    f.write(json.dumps(a, indent=4))
    # json.dump(a,f,indent=4)   # 和上面的效果一样

保存的文件效果:

\"\"

二. loads 和 load 
loads和load  反序列化方法
       loads 只完成了反序列化,
       load 只接收文件描述符,完成了读取文件和反序列化

 查看源码:
def loads(s, encoding=None, cls=None,  _hook=None, parse_float=None, parse_int=None, parse_constant=None,  _pairs_hook=None, **kw):
    \"\"\"Deserialize ``s`` (a ``str`` instance containing a JSON document) to a Python  .
       将包含str类型的JSON文档反序列化为一个python对象\"\"\"
def load(fp, cls=None,  _hook=None, parse_float=None, parse_int=None, parse_constant=None,  _pairs_hook=None, **kw):
    \"\"\"Deserialize ``fp`` (a ``.read()``-supporting file-like   containing a JSON document) to a Python  .
        将一个包含JSON格式数据的可读文件饭序列化为一个python对象\"\"\"

实例:

>>> json.loads(\'{\"name\":\"Tom\", \"age\":23}\')
{\'age\': 23, \'name\': \'Tom\'}
import json
with open(\"test.json\", \"r\", encoding=\'utf-8\') as f:
    aa = json.loads(f.read())
    f.seek(0)
    bb = json.load(f)    # 与 json.loads(f.read())
print(aa)
print(bb)

# 输出:
{\'name\': \'Tom\', \'age\': 23}
{\'name\': \'Tom\', \'age\': 23}

三. json 和 pickle 模块
json模块和pickle模块都有  dumps、dump、loads、load四种方法,而且用法一样。
不用的是json模块序列化出来的是通用格式,其它编程语言都认识,就是普通的字符串,
而picle模块序列化出来的只有python可以认识,其他编程语言不认识的,表现为乱码
不过picle可以序列化函数,但是其他文件想用该函数,在该文件中需要有该文件的定义(定义和参数必须相同,内容可以不同)

四. python对象(obj) 与json对象的对应关系

    +-------------------+---------------+
    | Python            | JSON          |
    +===================+===============+
    | dict              |          |
    +-------------------+---------------+
    | list, tuple       | array         |
    +-------------------+---------------+
    | str               | string        |
    +-------------------+---------------+
    | int, float        | number        |
    +-------------------+---------------+
    | True              | true          |
    +-------------------+---------------+
    | False             | false         |
    +-------------------+---------------+
    | None              | null          |
    +-------------------+---------------+

五. 总结

 1. j

收藏 打印