【python学习笔记】模块

1.模块的概念

  • 在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里就会越来越长,越来越不容易维护。
  • 为方便可维护的代码,我们将函数进行分组,放到不同的文件中去,这样代码就容易维护了
  • 一个.py文件就称为一个模块
  • 使用模块的最大好处就是提高了代码的可维护性
  • 编写程序时,可以使用模块,包含python内置的模块和第三方模块
  • 使用模块还可以有效避免了函数名和变量名冲突,相同名字的函数和变量名完全可以分别存储在不同的模块中

2.模块导入方法

① import语句

import module1[, module2[,... moduleN]

当我们使用import语句的时候,Python解释器是怎样找到对应的文件的呢?答案就是解释器有自己的搜索路径,存在sys.path里

② from…import 语句

from modname import name1[, name2[, ... nameN]]

这个声明不会把整个modulename模块导入到当前的命名空间中,只会将它里面的name1或name2单个引入到执行这个声明的模块的全局符号表

③ from…import* 语句

from modname import *

提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。大多数情况, Python程序员不使用这种方法,因为引入的其它来源的命名,很可能覆盖了已有的定义

3.包(package)

如果不同的人编写的模块名相同怎么办?为了避免模块名冲突,Python又引入了按目录来组织模块的方法,称为包(Package)

引入了包以后,只要顶层的包名不与别人冲突,那所有模块都不会与别人冲突

注意:每一个包目录下面都会有一个__init__.py的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录(文件夹),而不是一个包;__init__.py可以是空文件,也可以有Python代码,因为__init__.py本身就是一个模块,而它的模块名就是对应包的名字。

调用包就是执行包下的__init__.py文件

4. if __name__ == '__mian__':

if __name__=='__main__':
    print('ok')

如果我们是直接执行某个.py文件的时候,该文件中那么”__name__ == '__main__'“是True,但是我们如果从另外一个.py文件通过import导入该文件的时候,这时__name__的值就是我们这个py文件的名字而不是__main__

优点:在调试代码的时候,在”if __name__ == '__main__'“中加入一些我们的调试代码,我们可以让外部模块调用的时候不执行我们的调试代码,但是如果我们想排查问题的时候,直接执行该模块文件,调试代码能够正常运行!

##-------------cal.py
def add(x,y):
 
    return x+y
##-------------main.py
import cal      #from module import cal
 
def main():
 
    cal.add(1,2)
     
##--------------bin.py
from module import main
 
main.main()

5.常用模块

5.1-->>time模块

三种时间表示

在Python中,通常有这几种方式来表示时间:

  • 时间戳(timestamp) :通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。
  • 格式化的时间字符串
  • 元组(struct_time)   : struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)

import time

#时间戳  #计算
print(time.time())  #1531643499.8984566秒,从1970年算起

#结构化时间----当地时间
print(time.localtime())  #1.将时间戳转化为结构化时间 
#相当于print(time.localtime(time.time())),传入参数time.time()
print(time.localtime(1562589756))
t = time.localtime()
print(t.tm_year)
print(t.tm_wday)

#结构化时间----UTC时区
print(time.gmtime())  #2.将时间戳转化为结构化时间 

#将结构化时间转化为时间戳
print(time.mktime(time.localtime()))

#将结构化时间转化为字符串时间, 两个参数-->>1.转换成的时间显示格式 2.结构化时间
print(time.strftime("%Y-%m-%d %X",time.localtime())) 

#将字符串时间转化为结构化时间,两个参数-->>1.字符串时间 2.对应的时间格式
print(time.strptime("2018:07:15:16:58:55","%Y:%m:%d:%X")) 
print(time.strptime("2018:07:15:16:58:55","%Y:%m:%d:%X")) 

#把时间戳转化为一个固定显示时间方式,不用自定义
print(time.ctime())  #默认参数为时间戳time.time()

#把结构化时间转化为一个固定显示时间方式,不用自定义
print(time.asctime()) #默认参数为结构花时间time.localtime()
#线程推迟指定的时间运行,单位为秒
time.sleep(0.1)
#第一次调用,返回的是进程运行的实际时间,而第二次之后的调用是自第一次调用以后到现在的运行
#时间,即两次时间差。
time.clock()

5.2-->>random模块

import random

print(random.random())   #随机取0-1之间的浮点数
#0.91098352068857
print(random.randint(1,3)) #随机去[1,3]
#3
print(random.randrange(1,3)) #随机取[1,3)
#2
print(random.choice([1,'23',[4,5]])) #随机取一个
#[4, 5]
print(random.sample([1,'23',[4,5]],2)) #可以选两个,返回列表,参数2
#[1, [4, 5]]
print(random.uniform(1,3)) #任意范围内的浮点数
#1.0933861612113636

#打乱次序
item = [1,3,5,7,9]
random.shuffle(item)
print(item) #[5, 1, 7, 3, 9]

#写个验证码

def v_code():
    ret = ''
    for i in range(5):
	    num = random.randint(0,9)
	    #chr()将整形数字转换为对应的ascii
	    alf = chr(random.randint(65,122)) #(65,122)代表着A-Z a-z的字母
	    s = str(random.choice([num,alf]))
	    ret += s
    return ret

print(v_code())

5.3-->>os模块

import os

#获取当前工作目录,即python脚本工作的目录路径
print(os.getcwd())
#改变当前工作目录-->>相当于shell下cd
os.chdir('test') #os.chdir('dirname')
print(os.getcwd())
 #返回当前目录:('.')
print(os.curdir)
#获取当前目录的父目录字符串名
print(os.pardir)
#可生成多层递归目录
os.makedirs('test_1/test_2/test_3') #os.makedirs('dirname1/dirname2')
#若目录为空,则删除,并递归到上一级目录,若为空,则删除,以此类推
os.removedirs('test_1/test_2/test_3') #os.removedirs('dirname1')
#生成单级目录
os.mkdir('test1') #os.mkdir('dirname')
#删除单级空目录,若目录不为空则无法删除,报错
os.rmdir('test1') #os.rmdir('dirname')
#列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
print(os.listdir('test')) #os.listdir('dirname')
#删除一个文件
os.remove('123.txt')
#重命名文件/目录
os.rename('123.txt','456.txt') #os.rename("oldname","newname")
#获取文件/目录信息
print(os.stat("123.txt")) #os.stat('path/filename')

#os.sep    #输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
#os.linesep #输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
#os.pathsep  #输出用于分割文件路径的字符串 win下为;,Linux下为:
#os.name    #输出字符串指示当前使用平台。win->'nt'; Linux->'posix'

#os.system("bash command") 运行shell命令,直接显示
os.system("calc")
#os.environ  获取系统环境变量
print(os.environ)

#os.path.abspath(path)  返回path规范化的绝对路径
print(os.path.abspath('test'))

#os.path.split(path)  将path分割成目录和文件名二元组返回
print(os.path.split('test/456.txt'))
#os.path.dirname(path)  返回path的目录。其实就是os.path.split(path)的第一个元素
print(os.path.dirname('test/456.txt'))
#os.path.basename(path)  返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
print(os.path.basename('test/456.txt'))

#os.path.exists(path)  如果path存在,返回True;如果path不存在,返回False
print(os.path.exists('test/456.txt'))  #True
#os.path.isabs(path)  如果path是绝对路径,返回True
print(os.path.isabs('test/456.txt'))  #False
#os.path.isfile(path)  如果path是一个存在的文件,返回True。否则返回False
print(os.path.isfile('test/456.txt')) #True
#os.path.isdir(path)  如果path是一个存在的目录,则返回True。否则返回False
print(os.path.isdir('test/456.txt')) #False

#os.path.join(path1[, path2[, ...]])  将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
a = r'C:\Users\huang\Desktop\模块\test' 
b = r'456.txt'
print(os.path.join(a,b))

#os.path.getatime(path)  返回path所指向的文件或者目录的最后存取时间
#os.path.getmtime(path)  返回path所指向的文件或者目录的最后修改时间

5.4-->>sys模块

import sys

#命令行参数List,第一个元素是程序本身路径
#sys.argv
print(sys.argv)

command = sys.argv[1]
path = sys.argv[2]
#这样做可以无需在程序执行过程中执行命令,根据判断直接运行程序
if command == "post":
	pass
if command == "get":
	pass

#退出程序,正常退出时exit(0)     
sys.exit(n)

#获取Python解释程序的版本信息       
sys.version
print(sys.version)

#最大的Int值       
#sys.maxint

#返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值         
sys.path

#返回操作系统平台名称           
sys.platform


#实现进度条
import time
for i in range(50):
    sys.stdout.write('#') #写入缓存。最后执行完一次性打印到屏幕上
    time.sleep(0.1)
    sys.stdout.flush() #刷新

5.5-->>json和pickle

eval内置方法可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特殊类型的时候,eval就不管用了,所以eval的重点还是通常用来执行一个字符串表达式,并返回表达式的值

#正常处理数据 eval()

dic = '{"name":"alex"}'
f_write = open('123.txt','w')
f_write.write(dic)

f_read = open('123.txt','r')
data = f_read.read()
print(data)
data = eval(data)
print(data["name"])

① 序列化

  • 把对象(变量)从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上
  • 反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling

② json

如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便

起一个数据交换作用

JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下:

####处理数据成字符串,用于存储数据
import json

dic = {'name':'alex'} #-->{'name':'alex'}-->'{"name":"alex"}'
i = 8 #-->'8'
s = 'hello' #-->"hello"-->>'"hello"'
l = [11,22] #-->"[11,22]"
t = (22,33) #-->> "(22,33)"
#json将数据转换为字符串形式,单引号变双引号
data = json.dumps(dic)
print(data)
data = json.dumps(i)
print(data)
data = json.dumps(s)
print(data)
data = json.dumps(l)
print(data)
data = json.dumps(t)
print(data)

###将处理完成的数据写入
dic_str = json.dumps(dic)
f = open('456.txt','w')
f.write(dic_str)

###读取文件数据
import json
f_read = open("456.txt","r")
#json将字符串转换为存储之前的数据类型
data = json.loads(f_read.read())

print(data)
print(type(data))

注意:

import json
#dct="{'1':111}"#json 不认单引号
#dct=str({"1":111})#报错,因为str后生成的数据还是单引号:{'1': 111}

dct='{"1":"111"}'
print(json.loads(dct))

#:无论数据是怎样创建的,只要满足json格式,就可以json.loads出来,不一定非要dumps的数据才能loads

③pickle

#pickle
#-------------------------序列化

import pickle

dic={'name':'alvin','age':23,'sex':'male'}

print(type(dic))  #<class 'dict'>

j=pickle.dumps(dic)
print(type(j))  #<class 'bytes'>
print(j)

f=open('123.txt','wb')#注意是w是写入str,wb是写入bytes,j是'bytes'
f.write(j)
f.close()


#-------------------------反序列化
import pickle

f=open('123.txt','rb')

data=pickle.loads(f.read())

print(data['age'])

问题:pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据

5.6-->>shelve模块

shelve模块比pickle模块简单,只有一个open函数,返回类似字典的对象,可读可写;key必须为字符串,而值可以是python所支持的数据类型

import shelve
 
f = shelve.open(r'shelve')
 
f['stu1_info']={'name':'alex','age':'18'}
f['stu2_info']={'name':'alvin','age':'20'}
f['school_info']={'website':'oldboyedu.com','city':'beijing'}

f.close()

print(f.get('stu1_info')['age'])

5.7-->>xml模块

xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单
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('123.xml')
root = tree.getroot()
print(root.tag)

#遍历xml文档
for i in root:
	print(i.tag,i.attrib)
	for j in i:
		print(j.tag,j.attrib)

#只遍历year节点
for node in root.iter('year'):
	print(node.tag,node.text)

#-----------------------------------------------------
import xml.etree.ElementTree as ET

tree = ET.parse('123.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("123.xml")

#删除
for country in root.findall('country'):
	rank = int(country.find('rank').text)
	if rank > 50:
		root.remove(country)

tree.write('123.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 = '333'

et = ET.ElementTree(new_xml) #生成文档对象
et.write("456.xml",encoding="utf-8",xml_declaration=True)

ET.dump(new_xml) #打印生成格式

5.8-->>configparser模块

import configparser

config = configparser.ConfigParser() #实例化一个对象   config = {}

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'
topsecret['Forward'] = 'no'
config['DEFAULT']['ForwardXll'] = 'yes'
with open('example.ini','w') as configfile:
	config.write(configfile)

生成配置文件:

[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
  
[bitbucket.org]
User = hg
  
[topsecret.server.com]
Port = 50022
ForwardX11 = no
#---------------->>增删改查

import configparser

config = configparser.ConfigParser()
#print(config.sections())

config.read('example.ini')  #读取文件解析
print(config.sections())  #['bitbucket.org', 'topsecret.server.com'],DEFAULT默认不打印出来
print('bytetong.com' in config)  #Fasle
print(config['bitbucket.org']['User'])   #hg
print(config['DEFAULT']['Compression']) #yes
print(config['topsecret.server.com']['ForwardXll'])  #no

#for key in config['bitbucket.org']:
	#print(key)   #默认会将DEFAULT内的内容打印出来

#user
#serveraliveinterval
#compression
#compressionlevel
#forwardxll   

print(config.options('bitbucket.org')) #['user', 'serveraliveinterval', 'compression', 'compressionlevel', 'forwardxll']
print(config.items('bitbucket.org')) #[('serveraliveinterval', '45'), ('compression', 'yes'), ('compressionlevel', '9'), ('forwardxll', 'yes'), ('user', 'hg')]
print(config.get('bitbucket.org','compression')) #yes

#-------------------删 改 增(config.write(open('i.cfg','w')))

config.add_section('yuan') #增加一个块
config.set('yuan','k1','11111') #增加键值

config.remove_section('topsecret.server.com') #删除一个块
config.remove_option('bitbucket.org','user') #删除键值对

config.write(open('i.cfg','w'))  #写入文件

5.9-->>hashlib模块

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

import hashlib

m = hashlib.md5()

m.update("hello".encode('utf-8'))

print(m.hexdigest())  #5d41402abc4b2a76b9719d911017c592 ,位数是固定的,与hello是对应的
#特点:
#单向,与明文是固定对应的
#不能逆推到明文
#可以将明文变为密文,密文和密文比较即可

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

import hashlib

m = hashlib.md5("fsfefesf".encode('utf-8')) #在md5随意增加自定义内容,进行加密

m.update("hello".encode('utf-8'))

print(m.hexdigest())  #48fafc83e435f90b8a3bc15f33eddc73
#可以叠加

import hashlib
 
m=hashlib.md5()# m=hashlib.sha256()
 
m.update('hello'.encode('utf8'))
print(m.hexdigest())  #5d41402abc4b2a76b9719d911017c592
 
m.update('alvin'.encode('utf8')) #实际上是在上面update完的基础上再update
print(m.hexdigest())  #92a7e713c30abbb0319fa07da2a5c4af
 
m2=hashlib.md5()
m2.update('helloalvin'.encode('utf8')) #相当于两次update,结果一样
print(m2.hexdigest()) #92a7e713c30abbb0319fa07da2a5c4af
#sha256

import hashlib

hash = hashlib.sha256('fasfs555af'.encode('utf-8'))

hash.update('alex'.encode('utf-8'))
print(hash.hexdigest()) #ef22baec6fbe74837d0b2f40b64d54cc16118a3e87b263261e9d54926dad971d

#hmac模块,内部对我们创建的key和内容再进行处理和加密
import hmac

h = hmac.new('alex'.encode('utf-8'))
h.update('hello'.encode('utf-8'))
print(h.hexdigest()) #c28dbb0cd8e52d54fdcbbff08a5d2dc0

5.10-->>logging模块

① 简单应用

import logging

#正常实现
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')

#输出
#WARNING:root:warning message
#ERROR:root:error message
#CRITICAL:root:critical message
'''
默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于
WARNING级别的日志,这说明默认的日志级别设置为WARNING
(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET),
默认的日志格式为日志级别:Logger名称:用户输出消息。
'''

② 灵活配置日志级别,日志格式,输出位置

#--------------------->>>>>logging.basicConfig
#存储log文件

logging.basicConfig(

	level=logging.DEBUG, #调整日志级别
	filename="logger.log", #默认文件写入为追加模式
	filemode="w",  #文件写入为覆盖模式
	format="%(asctime)s %(filename)s [%(lineno)d] %(message)s"
)

logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
basicConfig的参数:

1.filename:即日志输出的文件名,如果指定了这个信息之后,实际上会启用 FileHandler,而不再是 StreamHandler,这样日志信息便会输出到文件中了
2.filemode:这个是指定日志文件的写入方式,有两种形式,一种是 w,一种是 a,分别代表清除后写入和追加写入。
3.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。
    %(processName)s:打印线程名称。
    %(module)s:打印模块名称。
    %(message)s:打印日志信息。
4.datefmt:指定时间的输出格式。
5.style:如果 format 参数指定了,这个参数就可以指定格式化时的占位符风格,如 %、{、$ 等。
6.level:指定日志输出的类别,程序会输出大于等于此级别的信息。
7.stream:在没有指定filename的时候会默认使用 StreamHandler,这时 stream 可以指定初始化的文流。
8.handlers:可以指定日志处理时所使用的 Handlers,必须是可迭代的。

③ logger对象

logging.basicConfig()(用默认日志格式(Formatter)为日志系统建立一个默认的流处理器(StreamHandler),设置基础配置(如日志级别等)并加到root logger(根Logger)中)这几个logging模块级别的函数,另外还有一个模块级别的函数是logging.getLogger([name])(返回一个logger对象,如果没有指定名字将返回root logger)

import logging

logger=logging.getLogger() #返回一个logger对象

fh=logging.FileHandler("test_log")  #写入文件
ch=logging.StreamHandler() #输出到控制台

fm=logging.Formatter("%(asctime)s-%(message)s") #定义格式

fh.setFormatter(fm) 
ch.setFormatter(fm)

logger.addHandler(fh) #logger对象可以添加多个fh和ch对象
logger.addHandler(ch)

logger.setLevel("DEBUG") #设置日志级别

logger.debug("hello")
logger.info("hello")
logger.warning("hello")
logger.error("hello")
logger.critical("hello")

#####封装成一个函数形式

def logger():
    logger=logging.getLogger() #返回一个logger对象

    fh=logging.FileHandler("test_log")  #写入文件
    ch=logging.StreamHandler() #打印到屏幕上

    fm=logging.Formatter("%(asctime)s-%(message)s") #定义格式

    fh.setFormatter(fm) 
    ch.setFormatter(fm)

    logger.addHandler(fh) #logger对象可以添加多个fh和ch对象
    logger.addHandler(ch)

    logger.setLevel("DEBUG") #设置日志级别

    return logger

logger = logger()
logger.debug("hello")
logger.info("hello")
logger.warning("hello")
logger.error("hello")
logger.critical("hello")
#两个对象
import logging

logger=logging.getLogger() #返回一个logger对象

fh=logging.FileHandler("test_log")  #写入文件
ch=logging.StreamHandler() #输出到控制台

fm=logging.Formatter("%(asctime)s-%(message)s") #定义格式

fh.setFormatter(fm) 
ch.setFormatter(fm)

logger.addHandler(fh) #logger对象可以添加多个fh和ch对象
logger.addHandler(ch)

logger.setLevel("DEBUG") #设置日志级别

logger.debug("hello")
logger.info("hello")
logger.warning("hello")
logger.error("hello")
logger.critical("hello")

logger1 = logging.getLogger('mylogger')
logger1.setLevel(logging.DEBUG)

logger2 = logging.getLogger('mylogger')
logger2.setLevel(logging.INFO)

logger1.addHandler(fh)
logger1.addHandler(ch)

logger2.addHandler(fh)
logger2.addHandler(ch)

logger1.debug('logger1 debug message')
logger1.info('logger1 info message')
logger1.warning('logger1 warning message')
logger1.error('logger1 error message')
logger1.critical('logger1 critical message')
  
logger2.debug('logger2 debug message')
logger2.info('logger2 info message')
logger2.warning('logger2 warning message')
logger2.error('logger2 error message')
logger2.critical('logger2 critical message')

④ Filter

限制只有满足过滤规则的日志才会输出,比如我们定义了filter = logging.Filter('a.b.c'),并将这个Filter添加到了一个Handler上,则使用该Handler的Logger中只有名字带a.b.c前缀的Logger才能输出其日志

filter = logging.Filter('mylogger') 

logger.addFilter(filter)

#这是只对logger这个对象进行筛选

#如果想对所有的对象进行筛选,则:

filter = logging.Filter('mylogger') 

fh.addFilter(filter)

ch.addFilter(filter)

#这样,所有添加fh或者ch的logger对象都会进行筛选
import logging

logger = logging.getLogger()
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log')

# 再创建一个handler,用于输出到控制台
ch = logging.StreamHandler()

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

fh.setFormatter(formatter)
ch.setFormatter(formatter)

# 定义一个filter
filter = logging.Filter('mylogger')
fh.addFilter(filter)
ch.addFilter(filter)

# logger.addFilter(filter)
logger.addHandler(fh)
logger.addHandler(ch)


logger.setLevel(logging.DEBUG) #设置日志级别

logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')

##################################################
logger1 = logging.getLogger('mylogger')
logger1.setLevel(logging.DEBUG)

logger2 = logging.getLogger('mylogger')
logger2.setLevel(logging.INFO)

logger1.addHandler(fh)
logger1.addHandler(ch)

logger2.addHandler(fh)
logger2.addHandler(ch)

logger1.debug('logger1 debug message')
logger1.info('logger1 info message')
logger1.warning('logger1 warning message')
logger1.error('logger1 error message')
logger1.critical('logger1 critical message')

logger2.debug('logger2 debug message')
logger2.info('logger2 info message')
logger2.warning('logger2 warning message')
logger2.error('logger2 error message')
logger2.critical('logger2 critical message')
#coding:utf-8  
import logging  
  
# 创建一个logger    
logger = logging.getLogger()  
  
logger1 = logging.getLogger('mylogger')  
logger1.setLevel(logging.DEBUG)  
  
logger2 = logging.getLogger('mylogger')  
logger2.setLevel(logging.INFO)  
  
logger3 = logging.getLogger('mylogger.child1')  
logger3.setLevel(logging.WARNING)  
  
logger4 = logging.getLogger('mylogger.child1.child2')  
logger4.setLevel(logging.DEBUG)  
  
logger5 = logging.getLogger('mylogger.child1.child2.child3')  
logger5.setLevel(logging.DEBUG)  
  
# 创建一个handler,用于写入日志文件    
fh = logging.FileHandler('/tmp/test.log')  
  
# 再创建一个handler,用于输出到控制台    
ch = logging.StreamHandler()  
  
# 定义handler的输出格式formatter    
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')  
fh.setFormatter(formatter)  
ch.setFormatter(formatter)  
  
#定义一个filter  
#filter = logging.Filter('mylogger.child1.child2')  
#fh.addFilter(filter)    
  
# 给logger添加handler    
#logger.addFilter(filter)  
logger.addHandler(fh)  
logger.addHandler(ch)  
  
#logger1.addFilter(filter)  
logger1.addHandler(fh)  
logger1.addHandler(ch)  
  
logger2.addHandler(fh)  
logger2.addHandler(ch)  
  
#logger3.addFilter(filter)  
logger3.addHandler(fh)  
logger3.addHandler(ch)  
  
#logger4.addFilter(filter)  
logger4.addHandler(fh)  
logger4.addHandler(ch)  
  
logger5.addHandler(fh)  
logger5.addHandler(ch)  
  
# 记录一条日志    
logger.debug('logger debug message')  
logger.info('logger info message')  
logger.warning('logger warning message')  
logger.error('logger error message')  
logger.critical('logger critical message')  
  
logger1.debug('logger1 debug message')  
logger1.info('logger1 info message')  
logger1.warning('logger1 warning message')  
logger1.error('logger1 error message')  
logger1.critical('logger1 critical message')  
  
logger2.debug('logger2 debug message')  
logger2.info('logger2 info message')  
logger2.warning('logger2 warning message')  
logger2.error('logger2 error message')  
logger2.critical('logger2 critical message')  
  
logger3.debug('logger3 debug message')  
logger3.info('logger3 info message')  
logger3.warning('logger3 warning message')  
logger3.error('logger3 error message')  
logger3.critical('logger3 critical message')  
  
logger4.debug('logger4 debug message')  
logger4.info('logger4 info message')  
logger4.warning('logger4 warning message')  
logger4.error('logger4 error message')  
logger4.critical('logger4 critical message')  
  
logger5.debug('logger5 debug message')  
logger5.info('logger5 info message')  
logger5.warning('logger5 warning message')  
logger5.error('logger5 error message')  
logger5.critical('logger5 critical message')

应用:

import time
import logging
from config import settings


def get_logger(card_num, struct_time):

    if struct_time.tm_mday < 23:
        file_name = "%s_%s_%d" %(struct_time.tm_year, struct_time.tm_mon, 22)
    else:
        file_name = "%s_%s_%d" %(struct_time.tm_year, struct_time.tm_mon+1, 22)

    file_handler = logging.FileHandler(
        os.path.join(settings.USER_DIR_FOLDER, card_num, 'record', file_name),
        encoding='utf-8'
    )
    fmt = logging.Formatter(fmt="%(asctime)s :  %(message)s")
    file_handler.setFormatter(fmt)

    logger1 = logging.Logger('user_logger', level=logging.INFO)
    logger1.addHandler(file_handler)
    return logger1

5.11-->>re模块

正则表达式(或 RE)是一种小型的、高度专业化的编程语言,在Python中它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行

字符匹配(普通字符,元字符):

①普通字符:大多数字符和字母都会和自身匹配
              >>> re.findall('alvin','yuanaleSxalexwupeiqi')
                      ['alvin'] 

②元字符:. ^ $ * + ? { } [ ] | ( ) \

########元字符之. ^ $ * + ? { }
import re

#.可以匹配任意字符
ret = re.findall('a..in','helloalvin')
print(ret) #['alvin']
#匹配开头
ret=re.findall('^a...n','alvinhelloawwwn')
print(ret) #['alvin']
#匹配结尾
ret=re.findall('a...n$','alvinhelloawwwn')
print(ret) #['awwwn']
#匹配前一个字符[0,+oo]次
ret=re.findall('abc*','abcccc')  
print(ret) #['abcccc']
#匹配前一个字符[1,+oo]次
ret=re.findall('abc+','abccc')#[1,+oo]
print(ret) #['abccc']
 #匹配前一个字符[0,1]次
ret=re.findall('abc?','abccc')
print(ret) #['abc']
#匹配前一个字符{m.n},m-n次
ret=re.findall('abc{1,4}','abccc')
print(ret) #['abccc']

#注意:上面的* + ?等都是贪婪匹配,就是尽可能多的匹配

#可以在后面加个?,使其变为惰性匹配
# *? +? ??

re = re.findall('abc*?','abccccccc')
print(re) #['ab']
#元字符之字符集 []
import re
ret = re.findall('a[bc]d','acd')
print(ret)  #['acd']

ret = re.findall('[a-z]','acd')
print(ret)  #['a', 'c', 'd']

ret = re.findall('[.*+]','a.cd+') # *无效了
print(ret) #['.','+']

#在字符集里面有功能的符号:- ^ \

ret = re.findall('[1-9]','45dha3')
print(ret) #['4', '5', '3']

#非后面的字符进行匹配
ret = re.findall('[^ab]','45bdha3')
print(ret) #['4', '5', 'd', 'h', '3']

ret = re.findall('[\d]','45bdha3')
print(ret) #['4', '5', '3']
#元字符之转义字符 \
'''
反斜杠后边跟元字符去除特殊功能,比如\.
反斜杠后边跟普通字符实现特殊功能,比如\d

\d 匹配任何十进制数;它相当于类 [0-9]。
\D 匹配任何非数字字符;它相当于类 [^0-9]。
\s 匹配任何空白字符;它相当于类 [ \t\n\r\f\v]。
\S 匹配任何非空白字符;它相当于类 [^ \t\n\r\f\v]。
\w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
\W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]
\b 匹配一个特殊字符边界,比如空格 ,&,#等
'''

ret = re.findall('I\b','I am Huang')
print(ret) #[]
ret = re.findall(r'I\b','I am Huang')
print(ret) #['I']
ret = re.findall('I\\b','I am Huang')
print(ret) #['I']
ret = re.findall('^I','I am Huang')
print(ret) #['I']

ret = re.findall('I\b','Hello I Do It')
print(ret) #[]
ret = re.findall(r'I\b','Hello I Do It')
print(ret) #['I']
ret = re.findall('I\\b','Hello I Do It')
print(ret) #['I']

#转义字符的其他匹配
#---------------->>1
import re

#ret =re.findall('c\l','abc\le')
#print(ret) #[]
#ret = re.findall('c\\l','abc\le')
#print(ret) #[]
ret = re.findall('c\\\\l','abc\le')
print(ret) #['c\\l']
ret = re.findall(r'c\\l','abc\le')
print(ret) #['c\\l']

#---------------->>2
#之所以选择\b是因为\b在ASCII表中是有意义的
m = re.findall('\bblow','blow')
print(m) #[]
m = re.findall(r'\bblow','blow')
print(m) #['blow']
m = re.findall('\\bblow','blow')
print(m) #['blow']
m = re.findall('^blow','blow')
print(m) #['blow']

#元字符之分组 ()

m = re.findall(r'(ad)+','add')
print(m) #['ad']

ret = re.search('(?P<id>\d{2})/(?P<name>\w{3})','23/com')
print(ret) #得到匹配对象
print(ret.group())  #23/com
print(ret.group('id')) #23
print(ret.group('name')) #com

#元字符之 |
ret = re.search('(ab)|\d','rabdg8sd')
print(ret.group()) #ab

常用方法:

#re模块的常用方法
import re
# findall()
re.findall('a','alex pian') #返回所有满足匹配条件的结果,放在列表里
# search()
re.search('a','alex pian') 
#函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的
#对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None
# match()
re.match('a','abc').group() #同search,不过是在字符串开始处进行匹配
# split()
ret = re.split('[ab]','abcd') #先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
print(ret)  #['', '', 'cd']
ret = re.split(' ','I love python')
print(ret) #['I', 'love', 'python']
# sub()和subn()
ret = re.sub('\d','abc','alvin5yuan6')  #返回替换后的字符串
print(ret)  #alvinabcyuanabc
ret = re.sub('\d','abc','alvin5yuan6',1)
print(ret) #alvinabcyuan6
ret = re.subn('\d','abc','alvin5yuan6') #返回替换后的字符串及替换次数
print(ret)  #('alvinabcyuanabc', 2)
# compile编译
obj = re.compile('\d{3}') #得到正则表达式
ret = obj.search('abc123eeee')
print(ret) #<_sre.SRE_Match object; span=(3, 6), match='123'>
print(ret.group())  #123
# finditer()
ret = re.finditer('\d','gh123sd1341ab')
print(ret) #<callable_iterator object at 0x0000027B52B14630>迭代器

print(next(ret).group()) #1
print(next(ret).group()) #2
print(next(ret).group()) #3
print(next(ret).group()) #1

注意:

#额外问题

import re

ret = re.findall('abc+','abcabcabcfsfsgeesg123')
print(ret)  #['abc', 'abc', 'abc']
ret = re.findall('(abc)+','abcabcabcfsfsgeesg123')
print(ret)   #['abc'] #优先显示括号内部的结果,加?:就可以
ret = re.findall('(?:abc)+','abcabcabcfsfsgeesg123')
print(ret)  #['abcabcabc']
ret = re.findall('(?:abc)+','abcabcabcfsfsgeesg123')
print(ret)  ##['abcabcabc']

ret = re.findall('\d+','1111sfasf234afafasf555')
print(ret)  #['1111', '234', '555']
ret = re.findall('(\d)+','1111sfasf234afafasf555')
print(ret)    #['1', '4', '5'] #优先显示括号内部的结果,加?:就可以
ret = re.findall('(?:\d)+','1111sfasf234afafasf555')
print(ret) #['1111', '234', '555']

#---------------------------------------------------------------
import re

ret = re.findall('www.(baidu|163).com','www.baidu.com')
print(ret) #['baidu'] #这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可

ret = re.findall('www.(?:baidu|163).com','www.baidu.com')
print(ret) #['www.baidu.com']

ret = re.findall(r'www.(?:baidu|163).com','www.baidu.com')
print(ret) #['www.baidu.com']

应用:

#匹配简单标签
import re

print(re.findall("<(?P<tag_name>\w+)>(\w+)</(?P<ta_name>\w+)>","<h1>hello</h1>"))
print(re.search("<(?P<tag_name>\w+)>(\w+)</(?P<ta_name>\w+)>","<h1>hello</h1>").group())
print(re.search(r"<(\w+)>\w+</\w+>","<h1>hello</h1>").group())


#匹配出所有的整数
import re

#ret=re.findall(r"\d+{0}]","1-2*(60+(-40.35/5)-(-4*3))")
ret=re.findall(r"-?\d+\.\d*|(-?\d+)","1-2*(60+(-40.35/5)-(-4*3))")
ret.remove("")
print(ret)

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值