Python 第5周 - Python基础-常用模块介绍

内容

  1. Python模块详解
  2. import 使用
  3. time 与date time模块讲解
  4. random 模块讲解
  5. os 模块讲解
  6. sys模块和shutil模块讲解
  7. json、pickle、shelve模块讲解
  8. XML处理模块讲解
  9. PyYAML和configparse模块讲解
  10. hashlib模块讲解
  11. logging模块讲解
  12. re正则表达式模块讲解
  13. subprocess 模块讲解
  14. 作业需求
一、Python模块详解

     1、模块定义:

     类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合。而对于一个复杂的功能来,可能需要多个函数才能完成(函数又可以在不同的.py文件中),n个 .py 文件组成的代码集合就称为模块。  

     如:os 是系统相关的模块;file是文件操作相关的模块

    2、使用模块的好处:

  • 程序可扩展性
  • 减少程序代码
  • 方便程序架构的更改

    3、模块分类:

  • 自定义模块
  • 内置模块(又称为标准库)
  • 开源模块

    以下举例说明:

    (1)、自定义模块

  A、同级目录下,定义一个py文件

a、#同级目录下,定义一个py文件,为moduel.py,内容如下:
def chen(name):
    print("hello",name)

b、#起用一个新py文件进行,调用
import moduel  #导入定义的模块,

moduel.chen("chenchangqing") #执行模块中,子函数类型
输出:
hello chenchangqing

   注意:python 中每一个单独的文件,都可以被当做为模块。底层的代码级别 : 流程控制->函数->类->模块->包

   B、使用 `if __name__ == '__main__'` 调用

    if __name__ == '__main__' 模块中入口参数 ,告诉模块要调用什么函数,这个在单个py文件中进行应用。如下:   
def user(name):
    print("your name",name)
def password():
    print("your passwd:123456")

def number():
    print("your number:400-158-1678")

if __name__ == '__main__':  #定义入口
    A = input("your name :")
    user(A)
    password()
    number()

输出:
your name :chenchangqing
your name chenchangqing
your passwd:123456
your number:400-158-1678

    (2)、内置模块

   如:os 是系统相关的模块;file是文件操作相关的模块 ; sys 模块等都属于python内置模块, 本文后面会介绍常用的模块。

    (3)、开源模块

     a、下载安装

开源模块的安装,有两种方式
第一种,使用系统自带工具安装
1、yum  
2、pip3

第二种,是用源码安装
下载源码
解压源码
进入目录
编译源码    python setup.py build
安装源码    python setup.py install

注:在使用源码安装时,需要使用到gcc编译和python开发环境,所以,需要先执行:
yum install gcc
yum install python-devel

安装成功后,模块会自动安装到 sys.path 中的某个目录中,如:
/usr/lib/python3.5.1/site-packages/
开源模块安装

     b、模块导入

         与自定义模块导入的方式一样,使用import 、from .. import ..

     c、以paramiko 模块为例 

         paramiko是一个用于做远程控制的模块,使用该模块可以对远程服务器进行命令或文件操作,值得一说的是,fabric和ansible内部的远程管理就是使用的paramiko来现实。

安装 paramiko 模块:

1、使用系统工具安装
   pip3 install paramiko

或者
2、使用源码安装
# pycrypto,由于 paramiko 模块内部依赖pycrypto,所以先下载安装pycrypto
 
# 下载安装 pycrypto
wget http://files.cnblogs.com/files/wupeiqi/pycrypto-3.5.2.tar.gz
tar -xvf pycrypto-3.5.2.tar.gz
cd pycrypto-3.5.2
python setup.py build
python setup.py install
 
# 进入python环境,导入Crypto检查是否安装成功
 
# 下载安装 paramiko
wget http://files.cnblogs.com/files/wupeiqi/paramiko-1.10.1.tar.gz
tar -xvf paramiko-1.10.1.tar.gz
cd paramiko-1.10.1
python setup.py build
python setup.py install
 
# 进入python环境,导入paramiko检查是否安装成功
$ python3.5
>>> import paramiko  #不报错,说明已经导入成功
paramiko的使用:
A、执行命令 - 通过用户名、密码连接服务器
import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

ssh.connect(hostname="110.29.69.31",port=22,username="root", password="UByXfdadfsfsd")
stdin, stdout, stderr = ssh.exec_command("uptime")
print (stdout.read())

ssh.close()

输出:
b' 14:51:41 up 1 day,  2:37,  0 users,  load average: 0.00, 0.00, 0.00\n'
密码账号连接服务器
B、执行命令 - 通过密钥连接服务器
import  paramiko
import os

key_path =os.path.expanduser('/Users/mac/me/key/Identity') #定义密钥存放的路径
key_rsa = paramiko.RSAKey.from_private_key_file(key_path,password="chen!#%1203") #密钥如果需要密码,则需要添加 password="chen!#%1203"

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

ssh.connect(hostname="109.10.10.18", port=22, username="www",pkey=key_rsa) #pkey 是指定要读取的密钥
stdin, stdout,sdterr = ssh.exec_command('uptime')
print (stdout.read())
ssh.close()
输出:
b' 14:15:31 up 591 days, 22:54,  0 users,  load average: 0.00, 0.01, 0.00\n'

备注:
这里的key是通过crt生成的设置密码的,RSA Key有密码的话,所以在这里应用为,否则将会报无法识别的RSA KEY。
key_path =os.path.expanduser('/Users/mac/me/key/Identity') 
key_rsa = paramiko.RSAKey.from_private_key_file(key_path,password="chen!#%1203") 

而如果你用的是RSA的key,是用sh-keygen -t rsa来指定的,则不需要要添加password="chen!#%1203"
通过密钥来登录
C、上传或者下载文件 - 通过用户名和密码
#上传:
import os,sys
import paramiko

t = paramiko.Transport(("192.168.3.52",22))
t.connect(username="root", password="fafdaa")
sftp = paramiko.SFTPClient.from_transport(t)
sftp.put('/Users/mac/me/ssh1.py','/tmp/ssh1.py') #前一个源路径、后一个是目标路径

t.close()

查看服务器上信息比对:
[root@VM_centos tmp]# pwd
/tmp
[root@VM_centos tmp]# ls
cvm_init.log  net_affinity.log  setRps.log  ssh1.py

#下载:
import os,sys
import paramiko

t = paramiko.Transport(("119.29.69.31",22))
t.connect(username="root", password="UByXcYZmVCIisHd5")
sftp = paramiko.SFTPClient.from_transport(t)
sftp.get('/tmp/ssh1.py','//Users/mac/me/sshbak.py') #前一个源路径、后一个是目标路径

t.close()
查看本地目录
CQ-Chen:me CQ_Chen$ pwd
/Users/mac/me
CQ-Chen:me CQ_Chen$ ls -l 
-rw-r--r--  1 CQ_Chen  staff  378 11 14 11:28 sshbak.py
通过密钥上传下载
D、上传或者下载文件 - 通过密钥
#上传
import  paramiko
import os

key_path =os.path.expanduser('/Users/mac/me/key/Identity')
key_rsa = paramiko.RSAKey.from_private_key_file(key_path,password="chen!#%1203")

t = paramiko.Transport(("109.10.10.98",22))
t.connect(username="www",pkey=key_rsa)

sftp = paramiko.SFTPClient.from_transport(t)
sftp.put("/Users/mac/me/109.10.10.98.sh","/tmp/ssh.sh")#源路径、目标路径

t.close()

服务器查看 
$ ls
ssh.sh

#下载
import  paramiko
import  os

key_path =os.path.expanduser('/Users/mac/me/key/Identity')
key_rsa = paramiko.RSAKey.from_private_key_file(key_path,password="chen!#%1203")

t = paramiko.Transport(("109.10.10.98",22))
t.connect(username="www",pkey=key_rsa)

sftp = paramiko.SFTPClient.from_transport(t)
sftp.get("/tmp/ssh.sh","/Users/mac/me/down.sh")

t.close()

注意:sftp.get  put  的使用
通过密钥上传下载
二、import 使用

     Python之所以应用越来越广泛,在一定程度上也依赖于其为程序员提供了大量的模块以供使用,如果想要使用模块,则需要导入。

     导入模块有一下几种方法:  

import module #可参考自定模块的方法
from module.xx.xx import xx
from module.xx.xx import xx as rename  
from module.xx.xx import *

举例:

 1 同目录下
 2 #定义模块,名称为module.py
 3 def user(name):
 4     print("your name",name)
 5 
 6 def password():
 7     print("your passwd:123456")
 8 
 9 def number():
10     print("your number:400-158-1678")
11 
12 #在另外一个python 文件中进行调用,文件名为test.py
13 from module import user
14 
15 user("Chen")   #在这里直接调用了函数名的。如果导入模块使用的是 import module 则这一步为 module.user("Chen"),前面要加入模块的前缀
16 输出:
17 your name Chen
同目录下模块调用
 1 #按照上面定义的,模块跟调用py文件分布在不同的 目录,进行调用
 2 def user(name):
 3     print("your name",name)
 4 def password():
 5     print("your passwd:123456")
 6 
 7 def number():
 8     print("your number:400-158-1678")
 9 
10 
11 #利用test.py进行调用
12 错误写法为
13 from moduel import user
14 
15 user("Chen")
16 输出报错、找不到模块
17 Traceback (most recent call last):
18   File "/Users/mac/PycharmProjects/untitled2/51CTO/5day/test.py", line 4, in <module>
19     from moduel import user
20 ImportError: No module named 'moduel'
21 
22 正确写法为:
23 import sys
24 sys.path.append("/Users/mac/PycharmProjects/untitled2/51CTO/5day1/")  #导入模块所在的目录
25 from moduel import user
26 
27 user("Chen")
28 输出:
29 your name Chen
不同目录之间的调用

 目录位置如截图:

备注:在模块所在的目录里面增加__init__.py文件,里面可以写import时执行的代码,当然也可以留空就可以。这是一个引用的文件,如果有三层目录,则每一层目录都要添加此文件,否则调用模块文件报错。

导入模块其实就是让Python解释器去解释那个py文件

  • 导入一个py文件,解释器解释该py文件
  • 导入一个包,解释器解释该包下的 __init__.py 文件 

  导入模块是根据那个路径作为基准来进行查找的呢。下面距举例:

import sys
print (sys.path)
输出:
['/Users/mac/PycharmProjects/untitled2/51CTO/5day', '/Users/mac/PycharmProjects/untitled2', '/Library/Frameworks/Python.framework/Versions/3.5/lib/python35.zip', '/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5', '/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/plat-darwin', '/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages']
以上是查找模块的顺序

如果sys.path路径列表没有你想要的路径,可以通过 sys.path.append('路径') 添加。

1 import sys 
2 import os
3 
4 pre_path = os.path.abspath('../') 
5 sys.path.append(pre_path)
三、time 与date time模块讲解

1、time模块讲解 

时间相关的操作,时间有三种表示方式:

  • 时间戳               1970年1月1日之后的秒,通常来说,时间戳表示的是从1970年1月1日00:00:00开始至今的时间差按秒计算的值。即:time.time()返回的是float类型。
  • 格式化的字符串    2014-11-11 11:11,    即:time.strftime('%Y-%m-%d')
  • 结构化时间          包含了struct_time元组共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)等 time.struct_time    即:time.localtime()、time.gmtime()

三者的关系:

三者之间的转换:

先以当前时间为准,快速认识三种形式的时间:
import time

print(time.time()) # 时间戳:1487130156.419527
print(time.strftime("%Y-%m-%d %X")) #格式化的时间字符串:'2017-11-15 11:40:53'
print(time.localtime()) #本地时区的struct_time
print(time.gmtime())    #UTC时区的struct_time

 第一幅图的转换

 <-----按图1转换时间-------------------->
#localtime([secs])  将一个时间戳转换为当前时区的struct_time。secs参数未提供,则以当前时间为准。
time.localtime()
time.localtime(1473525444.037215)

# gmtime([secs]) 和localtime()方法类似,gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。

#mktime(t) #将一个struct_time转化为时间戳。如:
print(time.mktime(time.localtime()))#1473525749.0


#strftime(format[, t]) 把一个代表时间的元组或者struct_time(如由time.localtime()和time.gmtime() 返回转化为格式化的时间字符串。如果t未指定,将入time.localtime() 如果元组中任何一个元素越界,ValueError的错误将会被抛出。
print(time.strptime('2017-11-15 16:37:06', '%Y-%m-%d %X'))

 #time.strptime(string[, format]) #把一个格式化时间字符串转化为struct_time。实际上它和strftime()是逆操作。
print(time.strftime("%Y-%m-%d %X", time.localtime()))#2016-09-11 00:49:56

#在这个函数中,format默认为:"%a %b %d %H:%M:%S %Y"。
time.struct_time(tm_year=2017, tm_mon=5, tm_mday=5, tm_hour=16, tm_min=37, tm_sec=6,tm_wday=3, tm_yday=125, tm_isdst=-1)

 按第二幅图转换:

#<--------------------------按图2转换时间---------->
# asctime([t]) : 把一个表示时间的元组或者struct_time表示为这种形式:'Sun Jun 20 23:21:05 1993'。
# 如果没有参数,将会将time.localtime()作为参数传入。
print(time.asctime())#Sun Sep 11 00:43:43 2016

# ctime([secs]) : 把一个时间戳(按秒计算的浮点数)转化为time.asctime()的形式。如果参数未给或者为
# None的时候,将会默认time.time()为参数。它的作用相当于time.asctime(time.localtime(secs))。
print(time.ctime())  # Sun Sep 11 00:46:38 2016
print(time.ctime(time.time()))  # Sun Sep 11 00:46:38 2016

格式化字符串的时间格式,可以参考help()文档,进行查询:

%a    Locale’s abbreviated weekday name.     
%A    Locale’s full weekday name.     
%b    Locale’s abbreviated month name.     
%B    Locale’s full month name.     
%c    Locale’s appropriate date and time representation.     
%d    Day of the month as a decimal number [01,31].     
%H    Hour (24-hour clock) as a decimal number [00,23].     
%I    Hour (12-hour clock) as a decimal number [01,12].     
%j    Day of the year as a decimal number [001,366].     
%m    Month as a decimal number [01,12].     
%M    Minute as a decimal number [00,59].     
%p    Locale’s equivalent of either AM or PM.    (1)
%S    Second as a decimal number [00,61].    (2)
%U    Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Sunday are considered to be in week 0.    (3)
%w    Weekday as a decimal number [0(Sunday),6].     
%W    Week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday are considered to be in week 0.    (3)
%x    Locale’s appropriate date representation.     
%X    Locale’s appropriate time representation.     
%y    Year without century as a decimal number [00,99].     
%Y    Year with century as a decimal number.     
%z    Time zone offset indicating a positive or negative time difference from UTC/GMT of the form +HHMM or -HHMM, where H represents decimal hour digits and M represents decimal minute digits [-23:59, +23:59].     
%Z    Time zone name (no characters if no time zone exists).     
%%    A literal '%' character.
格式化字符串的时间格式

 2、datetime 模块

主要做时间的加减使用

import datetime

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分  

c_time  = datetime.datetime.now()
print(c_time.replace(minute=3,hour=2)) #时间替换 
四、random 模块讲解

  1、Python中的random模块用于生成随机数,以下是经常用到的模块函数:

import random
   
print(random.random())    #随机打印(0,1)之间的float数数值,大于0且小于1之间的小数    
print(random.randint(1,3))  #[1,3] 表示大于等于1且小于等于3之间的整数    
print(random.randrange(1,3)) #[1,3) 表示大于等于1且小于3之间的整数    
print(random.choice([1,'23',[4,5]])) #随机选择1或者23或者[4,5]
print(random.sample([1,'23',[4,5]],2)) #随机选择列表的任意2个元素组合    
print(random.uniform(1,3)) #大于1小于3的小数,如1.927109612082716 
    
item=[1,3,5,7,9]
random.shuffle(item) #打乱item的顺序,重新排序  
print(item) 

2、编写网站验证码:

import random

checkcode = ''

for i in range(6):
    currnet = random.randrange(0,4) #取大于等于0且小于4的整数,取出来
    if currnet == i:
        tmp = chr(random.randint(65,90)) #chr 根据ascii码表进行打印英文字符 ,65-90表示大写字母从A-Z
        print(chr(65),chr(90))
        print("tmp1:",tmp)

    else:
        tmp=random.randint(0,4) #大于等于0且小于等于4之间的整数
        print("tmp2:",tmp)
    checkcode += str(tmp)

print(checkcode)

输出:
tmp2: 4
tmp2: 3
tmp2: 1
A Z
tmp1: C
tmp2: 0
tmp2: 0
431C00

备注:注意一下输出方式
五、os模块详解

os模块是与操作系统交互的一个接口。

常用的模块函数如下

常用模块
在Linux和Mac平台上,该函数会原样返回path,在windows平台上会将路径中所有字符转换为小写,并将所有斜杠转换为饭斜杠。
liunx或Mac
>>> os.getcwd()#获取当前路径
'/Users/mac'
>>> os.chdir("/Users/mac/me") #更改所在目录
>>> os.getcwd()
'/Users/mac/me'
>>> os.path.normcase("/Users/mac/me") #返回所在目录
'/Users/mac/me'

windows
>>> os.path.normcase('c:/windows\\system32\\')   
'c:\\windows\\system32\\'

去到其他的目录,或者使用 r
>>>os.chdir(r'c:\windows\system32\chen')

理解
规范化路径,如..和/
>>> os.path.normpath('c://windows\\System32\\../Temp/')   
'c:\\windows\\Temp'   

>>> a='/Users/jieli/test1/\\\a1/\\\\aa.py/../..'
>>> print(os.path.normpath(a))
/Users/jieli/test1

os路径处理 

#方式一:推荐使用
import os
#具体应用
import os,sys
possible_topdir = os.path.normpath(os.path.join(
    os.path.abspath(__file__),
    os.pardir, #上一级
    os.pardir,
    os.pardir
))
sys.path.insert(0,possible_topdir)


#方式二:不推荐使用
os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 
六、sys模块和shutil模块讲解

 1、SYS常用的系统模块

 1 sys.argv: 实现从程序外部向程序传递参数。
 2 
 3 sys.exit([arg]): 程序中间的退出,arg=0为正常退出 4 
 5 sys.getdefaultencoding(): 获取系统当前编码,一般默认为ascii。
 6 
 7 sys.setdefaultencoding(): 设置系统默认编码,执行dir(sys)时不会看到这个方法,在解释器中执行不通过,可以先执行reload(sys),在执行 setdefaultencoding('utf8'),此时将系统默认编码设置为utf8。(见设置系统默认编码 )
 8 
 9 sys.getfilesystemencoding(): 获取文件系统使用编码方式,Windows下返回'mbcs',mac下返回'utf-8'.
10 
11 sys.path: 获取指定模块搜索路径的字符串集合,可以将写好的模块放在得到的某个路径下,就可以在程序中import时正确找到。
12 
13 sys.platform: 获取当前系统平台。
14 sys.version   获取Python解释程序的版本信息
15 sys.maxint    最大的Int值
16 
17 sys.stdin,sys.stdout,sys.stderr: stdin , stdout , 以及stderr 变量包含与标准I/O 流对应的流对象. 如果需要更好地控制输出,而print 不能满足你的要求, 它们就是你所需要的. 你也可以替换它们, 这时候你就可以重定向输出和输入到其它设备( device ), 或者以非标准的方式处理它们

sys.argv

功能:在外部向内部传递参数。举例:

$ cat test.py 
import sys

print (sys.argv[0]) #默认获取脚本的明名称
print (sys.argv[1]) #获取外部传入的第一个参数
print (sys.argv[2]) #获取外部传入的第二个参数
print (sys.argv[3]) #获取外部传入的第三个参数

$ python3.5 test.py chen chang qing   #  以空格为分隔符,进行区分传入
test.py
chen
chang
qing

sys.exit(n)

功能:执行到主程序末尾,解释器自动退出,但是如果需要中途退出程序,可以调用sys.exit函数,带有一个可选的整数参数返回给调用它的程序,表示你可以在主程序中捕获对sys.exit的调用。(0是正常退出,其他为异常)

第一个方法:
import sys
def exitfun():
    print("hello world")

sys.exitfunc = exitfun()
print ("hello")

sys.exit(0) #  退出程序,不执行下面的操作

print ("there")
输出:
hello world
hello

第一个方法:
import sys
print ("chen1203")
try:
    sys.exit(1)
except SystemExit: #捕获退出的异常
    pass                  #捕获后,不做任何的操作
print("This is OK!!")
输出:
chen1203
This is OK!!   
sys.exit模块阻断

sys.path

功能:获取指定模块搜索路径的字符串集合,可以将写好的模块放在得到的某个路径下,就可以在程序中import时正确找到。

import sys
print(sys.path)
输出:
['/Users/mac/PycharmProjects/untitled2/51CTO/5day', '/Users/mac/PycharmProjects/untitled2', '/Library/Frameworks/Python.framework/Versions/3.5/lib/python35.zip', '/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5', '/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/plat-darwin', '/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/lib-dynload', '/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages']

使用的模块路径,不在默认路径里面,可以按下面方法执行:
sys.path.append("路径")
import 模块

sys.modules

功能:sys.modules是一个全局字典,该字典是python启动后就加载在内存中。每当程序员导入新的模块,sys.modules将自动记录该模块。当第二次再导入该模块时,python会直接到字典中查找,从而加快了程序运行的速度。它拥有字典所拥有的一切方法。

1 >>> import sys
2 # 这个时候os这个module已经被加载了,但是在当前作用域并不可见。
3 >>> sys.modules['os']
4 <module 'os' from '/usr/lib/python3.5/os.pyc'>

实现进度条的打印:

#指定宽度
print('[%-15s]' %'#')  #15s 指定宽度
print('[%-15s]' %'##')
print('[%-15s]' %'###')
print('[%-15s]' %'####')

#打印%
print('%s%%' %(100)) #第二个%号代表取消第一个%的特殊意义

#可传参来控制宽度
print('[%%-%ds]' %50) #[%-50s]
print(('[%%-%ds]' %50) %'#')
print(('[%%-%ds]' %50) %'##')
print(('[%%-%ds]' %50) %'###')

实例:

import sys
import time

def progress(percent,width=50):
    if percent >= 1:
       percent=1
    show_str=('[%%-%ds]' %width) %(int(width*percent)*'#')
    print('\r%s %d%%' %(show_str,int(100*percent)),file=sys.stdout,flush=True,end='')

data_size=1025#设计总数
recv_size=0
while recv_size < data_size:
    time.sleep(0.1) #模拟数据的传输延迟,注意时间间隔的设置
    recv_size += 1 #每次累计增加1个

    percent=recv_size/data_size #接收的比例
    progress(percent,width=100) #进度条的宽度70

输出:
[###########################                                           ] 39%

2、shutil常用的系统模块

功能:高级的 文件、文件夹、压缩包 处理模块。常用作文件copy 。

shutil.copyfileobj(fsrc, fdst[, length])
将文件内容拷贝到另一个文件中

import shutil
shutil.copyfileobj(open(
'/Users/mac/me/ssh.sh',"r"),open("/Users/mac/me/chen.sh","w"))

shutil.copyfile(src, dst)
拷贝文件

1 shutil.copyfile('f1.log', 'f2.log') #目标文件无需存在

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

1 shutil.copymode('f1.log', 'f2.log') #目标文件必须存在

shutil.copystat(src, dst)
仅拷贝状态的信息,包括:mode bits, atime, mtime, flags

1 shutil.copystat('f1.log', 'f2.log') #目标文件必须存在

shutil.copy(src, dst)
拷贝文件和权限

1 import shutil
2  
3 shutil.copy('f1.log', 'f2.log')

shutil.copy2(src, dst)
拷贝文件和状态信息

1 import shutil
2  
3 shutil.copy2('f1.log', 'f2.log')

shutil.ignore_patterns(*patterns)
shutil.copytree(src, dst, symlinks=False, ignore=None)
递归的去拷贝文件夹:

1 import shutil
2  
3 shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) #目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除 

软连接的拷贝:

1 import shutil
2 
3 shutil.copytree('f1', 'f2', symlinks=True, ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))

shutil.rmtree(path[, ignore_errors[, onerror]])
递归的去删除文件

1 import shutil
2  
3 shutil.rmtree('folder1')

shutil.move(src, dst)
递归的去移动文件,它类似mv命令,其实就是重命名。

1 import shutil
2  
3 shutil.move('folder1', 'folder3')

shutil.make_archive(base_name, format,...)

创建压缩包并返回文件路径,例如:zip、tar

创建压缩包并返回文件路径,例如:zip、tar

  • base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
  • 如 data_bak                       =>保存至当前路径
  • 如:/tmp/data_bak =>保存至/tmp/
  • format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
  • root_dir: 要压缩的文件夹路径(默认当前目录)
  • owner: 用户,默认当前用户
  • group: 组,默认当前组
  • logger: 用于记录日志,通常是logging.Logger对象
1 #将 /data 下的文件打包放置当前程序目录
2 import shutil
3 ret = shutil.make_archive("data_bak", 'gztar', root_dir='/data')
4   
5   
6 #将 /data下的文件打包放置指定到/tmp/目录
7 import shutil
8 ret = shutil.make_archive("/tmp/data_bak", 'gztar', root_dir='/data')

shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的,详细:

ZipFile

1 import zipfile
2 #压缩
3 z = zipfile.ZipFile("/Users/mac/me/key.zip","w")
4 z.write("/Users/mac/me/ssh.py")
5 z.close()
6 #解压
7 z = zipfile.ZipFile("/Users/mac/me/key.zip", 'r')
8 z.extractall(path='.')
9 z.close()

TarFile

 1 import tarfile
 2 
 3 # 压缩
 4 t=tarfile.open('/tmp/egon.tar','w') #压缩包名字、路径定义
 5 t.add('/test1/a.py',arcname='a.bak') #添加文件到压缩包里面
 6 t.add('/test1/b.py',arcname='b.bak')
 7 t.close()
 8 
 9 # 解压
10 t=tarfile.open('/tmp/egon.tar','r')
11 t.extractall('/egon')
12 t.close()

 

七、json、pickle、shelve模块讲解

json、pickle模块参考,第4周 序列化与反序列化

shelve模块讲解

     shelve是一额简单的数据存储方案,他只有一个函数就是open(),这个函数接收一个参数就是文件名,然后返回一个shelf对象,你可以用他来存储东西,就可以简单的把他当作一个字典,当你存储完毕的时候,就调用close函数来关闭。 

 1 import shelve
 2 
 3 f = shelve.open(r'/Users/mac/me/123.py')
 4 f["chen"] = ["chen","chang","qing"]
 5 f["chen"].append("ok")
 6 print (f["chen"])
 7 输出:
 8 ['chen', 'chang', 'qing']
 9 
10 
11 存储的OK到哪里去了呢?其实很简单,OK没有写回,你把['chen', 'chang', 'qing']存到了f["chen"],当你再次读取f["chen"]的时候,f["chen"]只。 是一个拷贝,而你没有将拷贝写回,所以当你再次读取f["chen"]的时候,它又从源中读取了一个拷贝,所以,你新修改的内容并不会出现在拷贝中,解决的办法就是,第一个是利用一个缓存的变量,如下所示
12 
13 temp = f["chen"]
14 temp.append("chen1203")
15 f["chen"] = temp
16 
17 print (f["chen"])
18 输出:
19 ['chen', 'chang', 'qing', 'chen1203'
八、XML处理模块讲解

      xml即可扩展标记语言,它可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。从结构上,很像HTML超文本标记语言。但他们被设计的目的是不同的,超文本标记语言被设计用来显示数据,其焦点是数据的外观。它被设计用来传输和存储数据,其焦点是数据的内容。那么Python是如何处理XML语言文件的呢?下面一起来看看Python常用内置模块之xml模块吧。 

     本文主要学习的ElementTree是python的XML处理模块,它提供了一个轻量级的对象模型。在使用ElementTree模块时,需要import xml.etree.ElementTree的操作。ElementTree表示整个XML节点树,而Element表示节点数中的一个单独的节点。

设定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模版

对XML文件进行读取:

 1 import xml.etree.ElementTree as ET
 2 
 3 
 4 tree = ET.parse("xmltest.xml")
 5 root = tree.getroot()
 6 print(root.tag) # 打印了标签
 7 
 8 print ("====================")
 9 
10 #遍历xml文档内容
11 for child in root:
12     print(child.tag, child.attrib)
13     for i in child:
14         print (i.tag, i.text)
15 
16 print("====================")
17 
18 #只遍历year节点
19 for node in root.iter("year"):
20     print(node.tag, node.text)
21 
22 输出:
23 data
24 ====================
25 country {'name': 'Liechtenstein'}
26 rank 2
27 year 2008
28 gdppc 141100
29 neighbor None
30 neighbor None
31 country {'name': 'Singapore'}
32 rank 5
33 year 2011
34 gdppc 59900
35 neighbor None
36 country {'name': 'Panama'}
37 rank 69
38 year 2011
39 gdppc 13600
40 neighbor None
41 neighbor None
42 ====================
43 year 2008
44 year 2011
45 year 2011
xml文件读取

对xml文档内容修改:

 1 import xml.etree.ElementTree as ET
 2 
 3 tree = ET.parse("xmltest.xml")
 4 root = tree.getroot()
 5 
 6 #修改
 7 
 8 for node in root.iter("year"):  #读取的是内存地址
 9     new_year = int(node.text) + 1#转换为数字类型 +1
10     node.text = str(new_year)
11     node.set("updated","yes") #指定需要修改的边标签值
12 
13 tree.write("xmltest.xml")
14 
15 #查看文件
16 <data>
17     <country name="Liechtenstein">
18         <rank updated="yes">2</rank>
19         <year updated="yes">2012</year> #在原来的基础上,加了1
20         <gdppc>141100</gdppc>
21         <neighbor direction="E" name="Austria" />
22         <neighbor direction="W" name="Switzerland" />
23     </country>
24     <country name="Singapore">
25         <rank updated="yes">5</rank>
26         <year updated="yes">2015</year>
27         <gdppc>59900</gdppc>
28         <neighbor direction="N" name="Malaysia" />
29     </country>
30     <country name="Panama">
31         <rank updated="yes">69</rank>
32         <year updated="yes">2015</year>
33         <gdppc>13600</gdppc>
34         <neighbor direction="W" name="Costa Rica" />
35         <neighbor direction="E" name="Colombia" />
36     </country>
37 </data>
xml文件修改

对xml文档内容删除:

 1 import xml.etree.ElementTree as ET
 2 
 3 tree = ET.parse("xmltest.xml")
 4 root = tree.getroot()
 5 
 6 
 7 #删除node
 8 for country in root.findall("country"):
 9      rank = int(country.find("rank").text)
10      print (rank)
11      if rank > 50:
12          root.remove(country)
13 tree.write("output.xml")
14 查看重新生成的文件:
15 <data>
16     <country name="Liechtenstein">
17         <rank updated="yes">2</rank>
18         <year updated="yes">2012</year>
19         <gdppc>141100</gdppc>
20         <neighbor direction="E" name="Austria" />
21         <neighbor direction="W" name="Switzerland" />
22     </country>
23     <country name="Singapore">
24         <rank updated="yes">5</rank>
25         <year updated="yes">2015</year>
26         <gdppc>59900</gdppc>
27         <neighbor direction="N" name="Malaysia" />
28     </country>
29 </data>
30 
31 把<rank updated="yes">69</rank>给删除了 
删除

创建xml文件

 1 import xml.etree.ElementTree as ET
 2 
 3 new_xml = ET.Element("namelist") #定义tag
 4 name = ET.SubElement(new_xml, "name", attrib={"enrolled": "yes"})
 5 age = ET.SubElement(name, "age", attrib={"checked": "no"})
 6 sex = ET.SubElement(name, "sex")
 7 sex.text = '33'
 8 name2 = ET.SubElement(new_xml, "name", attrib={"enrolled": "no"})
 9 age = ET.SubElement(name2, "age")
10 age.text = '19'
11 
12 et = ET.ElementTree(new_xml)  # 生成文档对象
13 et.write("test.xml", encoding="utf-8", xml_declaration=True)
14 
15 ET.dump(new_xml)  # 打印生成的格式
16 输出:
17 <namelist>
18     <name enrolled="yes">
19         <age checked="no" />
20         <sex>33</sex>
21     </name>
22     <name enrolled="no">
23         <age>19</age>
24     </name>
25 </namelist>
xml文件创建

 

九、PyYAML和configparse模块讲解

 YAML:此模块默认没有安装,需要用到模块,编译安装
YAML是一种用来表达数据序列的编程语言,它的主要特点包括:可读性强、语法简单明了、支持丰富的语言解析库、通用性强等。Ansible与Saltstack环境中配置文件都以YAML格式存在。下面是saltstack的配置:

1 file_roots: 
2   base:  
3    - /srv/salt/ 
4  dev:
5    - /srv/salt/dev  
6  prod:  
7    - /srv/salt

要通过YAML描述与Python的对应关系,从而方便读者了解YAML的层次及结构,最常见的是映射到Python中的列表(List)、字典(Dictionary)两种对象类型。下面通过块序列与块映射的示例详细说明。

1.块序列描述

块序列就是将描述的元素序列到Python的列表(List)中

 1 #/!/usr/bin/env python
 2 import yaml
 3 data=yaml.load(""" 
 4   - one
 5   - two
 6   - three
 7   - four
 8 """)
 9 print (data)
10 用“-”来分隔列表中的每个元素,运行结果如下:
11 # python yamltest.py 
12 ['one', 'two', 'three', 'four']
13 
14 15 
16 #/!/usr/bin/env python
17 import yaml
18 data=yaml.load(""" 
19   -
20    - one
21    - two
22    - three
23    - four
24   - 
25    - list
26    - dict
27    - set
28 """)
29 print (data)
30 显示如下:
31 python yamltest.py 
32 [['one', 'two', 'three', 'four'], ['list', 'dict', 'set']]
33 #返回的是list类型

2.块映射描述

块映射就是将描述的元素序列到Python的字典(Dictio-nary)中,格式为“键(key):值(value)”。

 1 #/!/usr/bin/env python
 2 
 3 import yaml
 4 data=yaml.load(""" 
 5  hero:
 6    me: 21
 7    mayun: 55
 8 """)
 9 print (type(data))
10 print (data)
11 结果:
12 <type 'dict'>
13 {'hero': {'me': 21, 'mayun': 55}}

YAML块序列与块映射是可以自由组合在一起的,它们之间可以相互嵌套,通过非常灵活的组合,可以帮助我们描述更加复杂的对象属性

 1 #注意空格和缩进
 2 #/!/usr/bin/env python
 3 
 4 import yaml
 5 data=yaml.load(""" 
 6   - hero:
 7      me: 21
 8      mayun: 55
 9   - name:
10      ME:
11         - 12
12         - 33
13 """)
14 print (data)
15 结果:
16 [{'hero': {'me': 21, 'mayun': 55}}, {'name': {'ME': [12, 33]}}]

案例:

 1 新建install.yaml文件
 2 输入一下内容
 3 name: Tom Smith
 4 age: 37
 5 spouse:
 6     name: Jane Smith
 7     age: 25
 8 children:
 9  - name: Jimmy Smith
10    age: 15
11  - name1: Jenny Smith
12    age1: 12
13 
14 #yaml读
15 import yaml
16 with open('disk.sls')as f:
17 s=yaml.load(f)
18 print(s)
19 {'spouse': {'name': 'Jane Smith', 'age': 25}, 'name': 'Tom Smith', 'children': [{'name': 'Jimmy Smith', 'age': 15}, {'age1': 12, 'name1': 'Jenny Smith'}], 'age': 37}
20 ============================================
21 
22 将字符串转入yaml格式放入yaml文件
23 file='test.yaml'
24 data={'host': {'ip01': {'two': '192.168.1.254', 'one': '192.168.1.2'}, 'ip00': '192.168.1.1'}, 'soft': {'apache': 2.2, 'php': 5.3, 'mysql': 5.2}}
25 f=open(file,'w')
26 yaml.dump(data,f)
27 f.close()
案例

 

ConfigParser模块

用于生成和修改常见配置文档,如常见的php.ini 文件、my.conf 文件。当前模块的名称在 python 3.x 版本中变更为 configparser。

配置文件的格式是: []包含的叫section,    section 下有option=value这样的键值

举例:

config.txt 文件测试操作:

1 [section1]
2 name = tank
3 age = 28
4 
5 [section2]
6 ip = 192.168.1.1
7 port = 8080

模拟增、删、改、查

 1 import configparser
 2 
 3 conf = configparser.ConfigParser()
 4 conf.read("config.txt")
 5 
 6 # 获取指定的section1, 指定的option的值
 7 name = conf.get("section1","name")
 8 print(name)
 9 age = conf.get("section1","age")
10 print(age)
11 
12 print("========================")
13 
14 #获取所有的section
15 setions_all = conf.sections()
16 print(setions_all)
17 
18 print("========================")
19 
20 #更改配置文件
21 #更新指定的值, 此时是更新内存中的值,并非更改文件中的值
22 conf.set("section1","age","30")
23 age_charge  = conf.get("section1","age")
24 print(age_charge)
25 
26 print("=========================")
27 
28 # 写入指定section, 增加新option的值
29 conf.set("section2", "IEPort", "8900")
30 IEPort = conf.get("section2","IEPort")
31 print(IEPort)
32 
33 print("=========================")
34 
35 # 添加新的 section
36 conf.add_section("section3")
37 conf.set("section3", "URL", "http://www.baidu.com")
38 sections_URL = conf.get("section3", "URL")
39 print(sections_URL)
40 
41 print("=========================")
42 
43 # 写回配置文件
44 conf.write(open("config.conf","w")) ###指定写到一个新文件中,如果更改的是原文件,指定原来的文件操作
45 
46 输出:
47 
48 tank
49 28
50 ========================
51 ['section1', 'section2']
52 ========================
53 30
54 =========================
55 8900
56 =========================
57 http://www.baidu.com
58 =========================

新文件效果:

 1 [section1]
 2 name = tank
 3 age = 30
 4 
 5 [section2]
 6 ip = 192.168.1.1
 7 port = 8080
 8 ieport = 8900
 9 
10 [section3]
11 url = http://www.baidu.com
十、hashlib模块讲解

 hashlib 模块主要用途用于加密线相关的操作,3版本里面替代md5和sha模块,主要提供SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法。

举例说明:

import hashlib

hash_md5 = hashlib.md5()
hash_md5.update(bytes('admin',encoding='utf-8'))

print (hash_md5.digest())  #二进制hash
print (hash_md5.hexdigest()) #16进制格式hash

print ("================================")

#hsha1
hash_sha1 = hashlib.sha1()
hash_sha1.update(b"admin")
print (hash_sha1.digest())
print (hash_sha1.hexdigest())

print ("================================")

#sha2
hash_sha2 = hashlib.sha256()
hash_sha2.update(b"admin")
print (hash_sha2.digest())
print (hash_sha2.hexdigest())

print ("================================")

#sha3
hash_sha2 = hashlib.sha384()
hash_sha2.update(b"admin")
print (hash_sha2.digest())
print (hash_sha2.hexdigest())

print ("================================")

#sha4
hash_sha4 = hashlib.sha384()
hash_sha4.update(b"admin")
print (hash_sha4.digest())
print (hash_sha4.hexdigest())


print ("================================")

#sha5
hash_sha5 = hashlib.sha512()
hash_sha5.update(b"admin")
print (hash_sha5.digest())
print (hash_sha5.hexdigest())

输出;
b'!#/)zW\xa5\xa7C\x89J\x0eJ\x80\x1f\xc3'
21232f297a57a5a743894a0e4a801fc3
================================
b'\xd03\xe2*\xe3H\xae\xb5f\x0f\xc2\x14\n\xec5\x85\x0cM\xa9\x97'
d033e22ae348aeb5660fc2140aec35850c4da997
================================
b'\x8civ\xe5\xb5A\x04\x15\xbd\xe9\x08\xbdM\xee\x15\xdf\xb1g\xa9\xc8s\xfcK\xb8\xa8\x1fo*\xb4H\xa9\x18'
8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918
================================
b'\x9c\xa6\x94\xa9\x02\x85\xc04C,\x95PB\x1b{\x9d\xbd\\\x0fKfs\xf0_m\xbc\xe5\x80R\xba \xe4$\x80A\x95n\xe8\xc9\xa2\xec\x9f\x10)\x0c\xdc\x07\x82'
9ca694a90285c034432c9550421b7b9dbd5c0f4b6673f05f6dbce58052ba20e4248041956ee8c9a2ec9f10290cdc0782
================================
b'\x9c\xa6\x94\xa9\x02\x85\xc04C,\x95PB\x1b{\x9d\xbd\\\x0fKfs\xf0_m\xbc\xe5\x80R\xba \xe4$\x80A\x95n\xe8\xc9\xa2\xec\x9f\x10)\x0c\xdc\x07\x82'
9ca694a90285c034432c9550421b7b9dbd5c0f4b6673f05f6dbce58052ba20e4248041956ee8c9a2ec9f10290cdc0782
================================
b'\xc7\xadD\xcb\xadv*]\xa0\xa4R\xf9\xe8T\xfd\xc1\xe0\xe7\xa5*8\x01_#\xf3\xea\xb1\xd8\x0b\x93\x1d\xd4rcM\xfa\xc7\x1c\xd3N\xbc5\xd1j\xb7\xfb\x8a\x90\xc8\x1f\x97Q\x13\xd6\xc7S\x8d\xc6\x9d\xd8\xde\x90w\xec'
c7ad44cbad762a5da0a452f9e854fdc1e0e7a52a38015f23f3eab1d80b931dd472634dfac71cd34ebc35d16ab7fb8a90c81f975113d6c7538dc69dd8de9077ec
hashlib代码说明

 Python 还有一个hmac模块,内部是对创建的 key 和 内容,进行处理然后再加密。

  散列消息鉴别码,简称HMAC,是一种基于消息鉴别码MAC(Message Authentication Code)的鉴别机制。使用HMAC时,消息通讯的双方,通过验证消息中加入的鉴别密钥K来鉴别消息的真伪;

  一般用于网络通信中消息加密,前提是双方先要约定好key,就像接头暗号一样,然后消息发送把用key把消息加密,接收方用key + 消息明文再加密,拿加密后的值 跟 发送者的相对比是否相等,这样就能验证消息的真实性,及发送者的合法性了。

 举例:

1 import  hmac
2 hash_hamc = hmac.new(b"Are you OK ", b"Yes")
3 print(hash_hamc.digest())
4 print(hash_hamc.hexdigest())
5 
6 输出:
7 
8 b'@\xc1\x97\xd9q\x0c\x14\xd9\x12\xcf\xbf\xa2\xfb\xc9\xf3L'
9 40c197d9710c14d912cfbfa2fbc9f34c

md5 加密案例:

md5对象,md5不能反解,但是加密是固定的,就是关系是一一对应,所以有缺陷,可以被对撞出来。

 1 #hashlib简单使用
 2 def md5(arg):#这是加密函数,将传进来的函数加密
 3     md5_pwd = hashlib.md5(bytes('abd',encoding='utf-8'))
 4     md5_pwd.update(bytes(arg,encoding='utf-8'))
 5     return md5_pwd.hexdigest()#返回加密的数据
 6 def log(user,pwd):#登陆时候时候的函数,由于md5不能反解,因此登陆的时候用正解
 7     with open('db','r',encoding='utf-8') as f:
 8         for line in f:
 9             u,p=line.strip().split('|')
10             if u ==user and p == md5(pwd):#登陆的时候验证用户名以及加密的密码跟之前保存的是否一样
11                 return True
12 def register(user,pwd):#注册的时候把用户名和加密的密码写进文件,保存起来
13     with open('db','a',encoding='utf-8') as f:
14         temp = user+'|'+md5(pwd)
15         f.write(temp)
16  
17 i=input('1表示登陆,2表示注册:')
18 if i=='2':
19     user = input('用户名:')
20     pwd =input('密码:')
21     register(user,pwd)
22 elif i=='1':
23     user = user = input('用户名:')
24     pwd =input('密码:')
25     r=log(user,pwd)#验证用户名和密码
26     if r ==True:
27         print('登陆成功')
28     else:
29         print('登陆失败')
30 else:
31     print('账号不存在')
十一、logging模块讲解

    程序都有记录日志的需求,并且日志中包含的信息即有正常的程序访问日志,还可能有错误、警告等信息输出,python的logging模块提供了标准的日志接口,你可以通过它存储各种格式的日志,logging的日志可以分为 debug()info()warning()error() and critical() 5个级别

import logging

logging.debug("This is debug message")
logging.info("This is info message")
logging.warning("This is warning message")
logging.error("This is error message")
logging.critical("This is critical message")
输出:
WARNING:root:This is warning message
ERROR:root:This is error message
CRITICAL:root:This is critical message
屏幕输出,只有CRITICAL\ERROR\ WARNING三种格式的日志进行输出。

默认情况下,logging将日志打印到屏幕,日志级别默认为WARNING;
日志级别大小关系为:CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET,当然也可以自己定义日志级别。

5种日志的定义:

DEBUG  详细信息,通常只有在诊断问题时才有意义。
INFO    信息确认事情按预期工作。
WARNING 指示意外事件发生,或在不久的将来指示某些问题(例如“磁盘空间不足”)。该软件仍在按预期工作。
ERROR   由于更严重的问题,软件不能执行某些功能。
CRITICAL  严重错误,表示程序本身可能无法继续运行

1、把日志记录到文件里面

import logging

logging.basicConfig(filename='logging.log',level=logging.INFO) 
logging.debug('This is debug message')
logging.info('This is info message')
logging.warning('This is warning message')
logging.error('This is ERROR message')
logging.critical('This is critical message')

查看文件记录:
INFO:root:This is info message
WARNING:root:This is warning message
ERROR:root:This is ERROR message
CRITICAL:root:This is critical message

备注:level=loggin.INFO 意思是,把日志纪录级别设置为INFO,也就是说,只有比日志是INFO或比INFO级别更高的日志才会被纪录到文件里。顺序大小为(日志级别大小关系为:CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET),如果要记录debug日志,只要设置level=logging.INFO 为level=logging.DEBUG

logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为:

filename: 用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。
filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
format:   指定handler使用的日志显示格式。
datefmt: 指定日期时间格式。
level:    设置rootlogger(后边会讲解具体概念)的日志级别
stream: 用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。 

2、对日志的输出,带上时间格式

import logging

logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S %p',
                    filename='logging.log')
logging.error("This is error message")

检查文件保存:
2017-11-28 16:18:40 PM This is error message
format='%(asctime)s %(message)s'定义的格式如下:

%(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、进阶的使用

主要分为四个部分:

  • Loggers:提供应用程序直接使用的接口
  • Handlers:将Loggers产生的日志传到指定位置
  • Filters:对输出日志进行过滤
  • Formatters:控制输出格式

  当项目中使用logging模块的时候肯定不能在这样一句句的写了,一般可能会抽象出一个模块来,这样比较有效一些。logging模块提供了四个类(Loggers,Formatters,Filtters,Handlers)来实现不同的功能。

 举例,把日志输出到屏幕上:

 1 import logging
 2 
 3 #创建 logger
 4 logger = logging.getLogger("my_log")
 5 logger.setLevel(logging.DEBUG)
 6 
 7 #创建克隆handler 并设置日志级别为debug
 8 ch = logging.StreamHandler()
 9 ch.setLevel(logging.DEBUG)
10 
11 #创建 formatter,控制日志输出格式
12 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
13 
14 #把formatter信息添加到ch
15 ch.setFormatter(formatter)
16 
17 #把ch 信息添加到 logger
18 logger.addHandler(ch)
19 
20 #举例
21 logger.debug("This is debug  message")
22 logger.info("This is Info  message")
23 logger.warning("This is Warning  message")
24 logger.error("This is Error  message")
25 
26 输出:
27 
28 2017-11-29 12:06:10,919 - my_log - DEBUG - This is debug  message
29 2017-11-29 12:06:10,920 - my_log - INFO - This is Info  message
30 2017-11-29 12:06:10,920 - my_log - WARNING - This is Warning  message
31 2017-11-29 12:06:10,920 - my_log - ERROR - This is Error  message

把日志输出到屏幕、同时保存在文件中:

 1 import logging
 2 
 3 #创建 logger
 4 logger = logging.getLogger("my_log")
 5 logger.setLevel(logging.DEBUG)
 6 
 7 #创建克隆handler 并设置日志级别为debug
 8 ch = logging.StreamHandler()
 9 ch.setLevel(logging.DEBUG)
10 
11 fh = logging.FileHandler("my_access.log")
12 fh.setLevel((logging.DEBUG))
13 
14 #创建 formatter
15 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
16 
17 #把formatter信息添加到ch、fh
18 ch.setFormatter(formatter)
19 fh.setFormatter(formatter)
20 
21 #把ch、fh 信息添加到 logger
22 logger.addHandler(ch)
23 logger.addHandler(fh)
24 
25 #举例
26 logger.debug("This is debug  message")
27 logger.info("This is Info  message")
28 logger.warning("This is Warning  message")
29 logger.error("This is Error  message")
30 
31 输出:
32 2017-11-29 12:24:06,000 - my_log - DEBUG - This is debug  message
33 2017-11-29 12:24:06,001 - my_log - INFO - This is Info  message
34 2017-11-29 12:24:06,001 - my_log - WARNING - This is Warning  message
35 2017-11-29 12:24:06,001 - my_log - ERROR - This is Error  message
同时输出到屏幕与文件中

 logging模块架构的文字解析:

Python 使用logging模块记录日志涉及四个主要类,使用官方文档中的概括最为合适:

logger提供了应用程序可以直接使用的接口;

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

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

formatter决定日志记录的最终输出格式。

logger
每个程序在输出信息之前都要获得一个Logger。
Logger通常对应了程序的模块名 
如比如聊天工具的图形界面模块可以这样获得它的Logger:
LOG=logging.getLogger(”chat.gui”)

核心模块表示:
LOG=logging.getLogger(”chat.kernel”)

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

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

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

可以设置的日志级别:
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:
1) logging.StreamHandler
使用这个Handler可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息。它的构造函数是:
StreamHandler([strm])
其中strm参数是一个文件对象。默认是sys.stderr


2) logging.FileHandler
和StreamHandler类似,用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件。它的构造函数是:
FileHandler(filename[,mode])
filename是文件名,必须指定一个文件名。
mode是文件的打开方式。参见Python内置函数open()的用法。默认是’a',即添加到文件末尾。

3) 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并不会被更名,而是被删除。


4) logging.handlers.TimedRotatingFileHandler
这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就 自动创建新的日志文件。重命名的过程与RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。它的构造函数是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。
interval是时间间隔。
when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:
S 秒
M 分
H 小时
D 天
W 每星期(interval==0时代表星期一)
midnight 每天凌晨
文字描述

 

TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。
interval是时间间隔。
when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:
S 秒
M 分
H 小时
D 天
W 每星期(interval==0时代表星期一)
midnight 每天凌晨

 如下:

import logging

from logging import handlers

logger = logging.getLogger(__name__)

log_file = "timelog.log"

fh = handlers.TimedRotatingFileHandler(filename=log_file,when="S",interval=5,backupCount=3)


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

fh.setFormatter(formatter)

logger.addHandler(fh)

logger.warning("test1")
logger.warning("test12")
logger.warning("test13")
logger.warning("test14")
练习

 

十二、re正则表达式模块讲解 

正则表达式:python  中为re 模块,正则表达式中,常用的函数为 :match() 、search()、sub()、subn()、split()、findall()

功能用法:

1 re.match       从头开始匹配
2 re.search      匹配包含
3 re.findall     把所有匹配到的字符放到以列表中的元素返回
4 re.splitall    以匹配到的字符当做列表分隔符
5 re.sub         匹配字符并替换

以下为正则表达式中,常用语法

 练习:

import re

#匹配文本中每个邮箱的,按照列表的形式打印
y = "123@qq.comchen@gmail.comchen@163.comqing@126.com"

res = re.findall('\w+@(?:qq|gmail|163|126).com',y) #
print(res)

print ("=================================")
#匹配一段文本中的每行的时间字符串,并按字典的形式输出
time = 'afafahsdjfhke0adshf1980-09-12asdfhh-0127889sdhflajhfw'
res_time1 = re.search(r'(?P<year>19[0-9]\d)-(?P<month>\d+)-(?P<days>\d+)',time).groupdict()
res_time2 = re.search(r'(?P<year>19[0-9]\d)-(?P<month>\d+)-(?P<days>\d+)',time).group()
res_time3 = re.search(r'(?P<year>19[0-9]\d)-(?P<month>\d+)-(?P<days>\d+)',time).groups()
print(res_time1)
print(res_time2)
print(res_time3)

#对比一下,使用groups、group、groupdict 的输出格式

print ("=================================")

#匹配一段文本中所有的身份证数字
a = '121414242,124331242423412413,2324123424,5674576,3522425,afsesdf'
res_auth = re.findall('\d{18}',a)
print(res_auth)

print ("=================================")
#匹配QQ号
b = '1002040,10201,23,23124234,12312408'
res_b0 = re.findall('\d\d{5,}',b)
res_b1 = re.findall('[0-9][0-9]{5,}',b)
print(res_b0)
print(res_b1)

#备注:\d 相等于 [0-9]
输出:
['123@qq.com', 'chen@gmail.com', 'chen@163.com', 'qing@126.com']
=================================
{'year': '1980', 'days': '12', 'month': '09'}
1980-09-12
('1980', '09', '12')
=================================
['124331242423412413']
=================================
['1002040', '23124234', '12312408']
['1002040', '23124234', '12312408']
re模块练习

 

十三、subprocess 讲解

   subprocess 模块是跟系统交互的模块(调用liunx系统命令用),是从python 2.4 版本中开始引入的模块。3.5版本后得到广泛使用,主要是用来取代一些旧的模块方法,如os.system、os.spwan*、os.popen*、commands.*等。subprocess 通过子进程来执行外部指令,并通过input/output/error 管道,获取子进程的执行的返回信息。

3.5版本中常用语法:
1、subprocess.call() #使用列表的方式,进行系统命令调用。在python3.5版本中,可以使用subprocess.run()(python2.*版本中,没有这个参数),两个参数结果显示一样。

1、调用系统命令
>>> import subprocess
>>> subprocess.run(['df','-h'])  #当做列表的形式,命令一个个传进去。
Filesystem      Size   Used  Avail Capacity iused      ifree %iused  Mounted on
/dev/disk1     112Gi   41Gi   70Gi    37%  970531 4293996748    0%   /
devfs          182Ki  182Ki    0Bi   100%     628          0  100%   /dev
map -hosts       0Bi    0Bi    0Bi   100%       0          0  100%   /net
map auto_home    0Bi    0Bi    0Bi   100%       0          0  100%   /home
CompletedProcess(args=['df', '-h'], returncode=0)
>>> subprocess.call(['df','-h'])
Filesystem      Size   Used  Avail Capacity iused      ifree %iused  Mounted on
/dev/disk1     112Gi   41Gi   70Gi    37%  970531 4293996748    0%   /
devfs          182Ki  182Ki    0Bi   100%     628          0  100%   /dev
map -hosts       0Bi    0Bi    0Bi   100%       0          0  100%   /net
map auto_home    0Bi    0Bi    0Bi   100%       0          0  100%   /home
0

2、命令中,如包含了管道符号,交由shell来处理。(两种模式均可使用)
>>> subprocess.run('df -h |grep disk1', shell=True) #当调用命令中,有管道符号是,交由shell来处理 。
/dev/disk1     112Gi   41Gi   70Gi    37%  975722 4293991557    0%   /
CompletedProcess(args='df -h |grep disk1', returncode=0)

>>> subprocess.call(args='df -h |grep disk1', shell=True) #执行命令,如果命令结果为0,就正常返回,否则抛异常
/dev/disk1     112Gi   41Gi   70Gi    37%  970581 4293996698    0%   /
0    
python subprocess_call

 2、subprocess.getstatusoutput() 接收字符串格式命令,返回元组形式,第1个元素是执行状态,第2个是命令结果 

>>> subprocess.getstatusoutput(['ls /bin/ls'])
(0, '/bin/ls')

3、 subprocess.getoutput()  #接收字符串格式命令,并返回结果(注意,返回结果,并不是打印)

>>> subprocess.getoutput('df -h |grep /dev')
'/dev/disk1     112Gi   41Gi   70Gi    37%  970645 4293996634    0%   /\ndevfs          182Ki  182Ki    0Bi   100%     628          0  100%   /dev'

>>> res=subprocess.check_output(['ls','-l']) #通过res赋值,在打印
>>> res
b'total 128\ndrwx------@  3 CQ_Chen  staff    102 12 26 10:49 Applications\ndrwx

调用subprocess.run(...):是推荐的常用方法,在大多数情况下能满足需求,但如果你可能需要进行一些复杂的与系统的交互的话,你还可以用subprocess.Popen()

4、subprocess.Popen() #在一些复杂场景中,我们需要将一个进程的执行输出作为另一个进程的输入。在另一些场景中,我们需要先进入到某个输入环境,然后再执行一系列的指令等。这个时候我们就需要使用到suprocess的Popen()方法。

可用参数:
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:是否使用shell来执行命令
cwd:用于设置子进程的当前目录
env:用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父进程中继承。
universal_newlines:不同系统的换行符不同,True -> 同意使用 \n
startupinfo与createionflags只在windows下有效将被传递给底层的CreateProcess()函数,用于设置子进程的一些属性,如:主窗口的外观,进程的优先级等等

操作:

举例1:/Users/mac/me目录下建一个目录为chenchangqing。
p = subprocess.Popen('mkdir chenchangqing',shell=True,cwd='/Users/mac/me')

举例2:
import subprocess
res = subprocess.Popen("sleep 5;echo 'hello'",shell=True,stdin=subprocess.PIPE,stderr=subprocess.PIPE)
out1 = res.wait() #检查执行进度, 直到程序执行完成。0为正常、1为异常。
out2 = res.poll() #检查子进程状态,0为正常、1为抛出异常。
print (out1,out2)

举例3: 输入进行某环境,依赖再输入,如:python3(指定在3版本下去执行命令)
import subprocess

#指python环境下,指定python环境执行命令
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

obj.stdin.write(b"print(1)\n") 
obj.stdin.write(b"print(2)\n")
obj.stdin.write(b"print(3)\n")
obj.stdin.write(b"print(4)\n")
obj.stdin.close()

cmd_out = obj.stdout.read()
obj.stdout.close()
cmd_error = obj.stderr.read() #读取输出的错误日志
obj.stderr.close()

print (cmd_out)
print (cmd_error)
输出:
b'1\n2\n3\n4\n'
b''

举例4:输入即可得到输出(结果),如:ifconfig (也是按照列表,把命令拆分进行输入) 
import subprocess
IP = subprocess.Popen(['ifconfig', 'en0'],stdin=subprocess.PIPE,stderr=subprocess.PIPE)
print(IP)
输出:
<subprocess.Popen object at 0x1007a5c18>
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
	ether 18:65:90:d5:e3:51 
	inet6 fe80::1091:3900:1e4:73dc%en0 prefixlen 64 secured scopeid 0x4 
	inet 10.9.15.233 netmask 0xfffffc00 broadcast 10.9.15.255
	nd6 options=201<PERFORMNUD,DAD>
	media: autoselect
	status: active

 其他操作:

import subprocess
process = subprocess.Popen('sleep 60',shell=True,stdout=subprocess.PIPE)
process.poll()    #检查子进程状态
process.kill()     #终止子进程
process.send_signal()    #向子进程发送信号
process.terminate()   #终止子进程

 

十四、作业需求

开发一个简单的python计算器

  1. 实现加减乘除及拓号优先级解析
  2. 用户输入 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等类似公式后,必须自己解析里面的(),+,-,*,/符号和公式(不能调用eval等类似功能偷懒实现),运算后得出结果,结果必须与真实的计算器所得出的结果一致

   re.search(r'\([^()]+\)',s).group()

 

转载于:https://www.cnblogs.com/chen170615/p/7825610.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值