29期第八周笔记

Week 8

本周学习主要内容包括python中的正则表达式(re模块),和ini文件,序列化与反序列化(部分)

习题

缓存应用场景

  1. 同样的函数参数一定得到同样结果,至少是一段时间内,同样输入得到同样结果
  2. 计算代价高,函数执行时间长
  3. 需要多次执行,每次计算代价高
  • cache

key的存储

  • 数据结构选取字典 key必须hashable
  • key能使用位置传参和关键字传参提供的实参
  • 位置传参本身有顺序
  • 关键字传参可无序,可以用字典收集
  • OrderedDict可以用,记录key的录入顺序
  • 可以不使用OrderedDict,对字典kv对按照key排序

装饰器的用途

  • 装饰器是AOP,面向切面编程(Aspect Oriented Programming)的思想的体现
  • 面向对象需要通过继承或组合依赖等方式调用一些功能,而这些功能代码可能在多个类中出现,会造成代码重复增加耦合,而AOP在需要的类或方法上切下,前后切入点可加入增强功能,让调用者和被调用者解耦
  • 不修改原有的业务代码,而给程序动态添加功能的技术

Python中的正则表达式

  • Python中使用re进行正则表达式的编写
  • 多行模式:re.M / re.MULTILINE
  • 单行模式:re.S / re.DOTALL

编译

  • re.compile(pattern,flags=0)
  • 设定flags,编译模式,返回正则表达式对象regex
  • pattern就是正则表达式字符串,flags是选项。正则表达式需要被编译,为了提高效率,这些编译后的结果被保存,下次使用同样pattern的时候就不需要再次编译。

单次匹配

  • re.match(pattern,string,flags=0)
  • regex.match(string[,pos[,endpos]])
  • match匹配从字符串的开头匹配,regex对象match方法可以重设开始和结束位置,返回match对象
s = """bottle\nbag\nbig\napple"""
r = re.match('b.+',s,re.S) #单行模式,贪婪 包括\n都被匹配
#匹配上,得到match类型实例,span(start,end)
#匹配不上,返回None

#,match单次搜索,并不做全文搜索,而且要求必须是从头匹配 索引0
r = re.match('a',s)
print(r) #None

r = re.match('^a',s)
print(r) #? 默认模式,一整行,没有a开头 None

r = re.match('^a',s,re.M)
print(r) #? 多行模式,可以看作多行,但影响^和$,所以依旧返回None
  • re.search(pattern,string,flags=0)
  • regex.search(string[,pos[,endpos]])
  • 从头搜索到第一个匹配,regex对象search方法可以重设开始和结束位置,返回match对象
#search是单次匹配,但是从index为0开始向后找到一次,找不到返回None
s = """bottle\nbag\nbig\napple"""
r = re.search('b',s)
print(type(r),r) #b 0 match实例

r = re.search('a',s) #index 0
print(type(r),r) #a 8

r = re.search('a',s,re.M) 
print(type(r),r) #a 8

r = re.search('^a',s,re.M) 
print(type(r),r) #a 15

r = re.search('^a',s) #index 0
print(type(r),r) #None
  • re.fullmatch(pattern,string,flags=0)
  • regex.fullmatch(string[,pos[,endpos]])
  • 真个字符串和正则表达式匹配
#fullmatch 要完全匹配,多了少了都不行
s = """bottle\nbag\nbig\napple"""
r = re.fullmatch('b.+',s)
print(type(r),r) #None

r = re.fullmatch('bag',s)
print(type(r),r) #None

r = re.fullmatch('b.+',s,re.S)
print(type(r),r) #全部

r = re.fullmatch('b.+',s,re.M)
print(type(r),r) #None

全文搜索

  • re.findall(pattern,string,flags=0)
  • regex.findall(string[,pos[,endpos]])
  • 对整个字符串,从左至右匹配,返回所有匹配项的列表
  • re.finditer(pattern,string,flags=0)
  • regex.finditer(string[,pos[,endpos]])
  • 对整个字符串,从左至右匹配,返回所有匹配项,返回迭代器
  • 注意每次迭代返回的是match对象

匹配替换

  • re.sub(pattern,replacement,string,count=0,flags=0)
  • regex.sub(replacement,string,count=0)
  • 使用pattern对字符串string进行匹配,对匹配项使用repl替换
  • replacement可以是string、bytes、function
#sub 模式替换,可以指定至多替换的次数,返回替换结果
s = """bottle\nbag\nbig\napple"""
r=re.sub('b\w+','magedu',s,10)
print(type(r),r)
--------------------------------
<class 'str'> magedu
magedu
magedu
apple
  • re.subn(pattern,replacement,string,count=0,flags=0)
  • regex.subn(replacement,string,count=0)
  • 同sub返回一个元组(new_string,number_of_subs_made)
#subn 模式替换,可以指定至多替换的次数,返回一个元组 (替换结果,替换次数)
s = """bottle\nbag\nbig\napple"""
r=re.subn('b\w+','magedu',s,1)
print(type(r),r)

分组

  • 使用小括号的pattern捕获的数据被放到了组group中
  • match、search函数返回match对象;findall返回字符串列表;finditer返回一个个match对象
  • 如果pattern中使用了分组,如果有匹配结果,会在match对象中
  1. 使用**group(N)**方式返回对应分组,1到N是对应的分组,0返回整个匹配的字符串,N不写缺省为0
  2. 如果使用了命名分组,可以使用**group(‘name’)**的方式取分组
  3. 也可以使用groups()返回所有组
  4. 使用groupdict()返回所有命名的分组
#group 分组,匹配是前提,要先有匹配对象
s = """bottle\nbag\nbig\napple"""
m = re.match('b\w+',s) #分组看正则表达式里有没有括号
print(m) #0,6 bottle

m = re.match('(b)(\w+)',s)
print(m.groups()) #取分组们

m = re.search('^(a)(\w+)',s,re.M)
print(m.groups()) 

m = re.search('^a\w+',s,re.M)
print(m.groups())
print(m)

m = re.search('^a\w+',s,re.M)
print(m.groups())
print(m.group(0)) #和m.groups()等价,组0表示match
print(m)
#print(m.group(1)) #空元组
#命名分组
s = """bottle\nbag\nbig\napple"""
m = re.search('a(?P<tail>\w+)',s,re.M)
if m:
    print(m.groups()) #取分组们
    print(m.group(0)) #空元组 和m.groups()等价,组0表示match
    print(m)
    print(m.group()) #组,组号,1开始

分割字符串

  • 字符串的分割函数split,太难用,不能指定多个字符进行分割
  • re.split(pattern,string,maxsplit=0,flags=0)
#split 分割,要指定分隔符
s = """bottle\nbag\nbig\napple"""
print(s.split()) # \s+
print(s.split('\n'))
print(s.split('\s+'))
print(s.split('\n\t '))
-----------------------------------------
['bottle', 'bag', 'big', 'apple']
['bottle', 'bag', 'big', 'apple']
['bottle\nbag\nbig\napple']
['bottle\nbag\nbig\napple']

CSV模块

  • comma seperated values
  • delimiter 列分隔符,逗号
  • lineterminator 行分隔符, \r\n
  • quotechar 字段的引用符号,缺省为“”双引号
  • 双引号的处理:

doublequote:双引号的处理,默认为True。如果碰到数据中有双引号,而quotechar也是双引号,True则使用两个双引号表示,False表示使用转义字符将作为双引号的前缀
escapecahr:一个转义字符,默认为None
writer:=csv.writer(f,doublequote=False,escapechar=’@’)遇到双引号则必须提供转移字符

  • quoting指定双引号的规则:

QUOTE_ALL 所有字段
QUOTE_MINIMAL 特殊字符字段,Excel方言使用该规则
QUOTE_NONNUMERIC 非数字字段
QUOTE_NONE 都不使用引号

ini文件处理

  • 作为配置文件,ini文件格式很流行(MySql)
  • 中括号里称为section,译作节、区、段;每个section内都是key=value形成的键值对,key称为option选项
  • DEFAULT是缺省section的名字,必须大写

configparser

import configparser

cfg = configparser.ConfigParser()
#配置文件解析器对象
print(cfg)
r = cfg.read('mysql.ini')
print(r)

#section
for x in cfg.sections(): #返回是所有section,但不含特殊的缺省section
    print(type(x),x)
    print(cfg.options(x))  #每一个section下的options,包含缺省
print('='*30)
for k,v in cfg.items(): #items()迭代,包含DEFAULT
    print(type(k),k) #k str
    print(type(v),v) #v section对象
    print(cfg.items(k)) #二元组克爹大对象,OrderedDict对象
    print('-'*30)

print(cfg.has_option('mysqld','a'))
# 取值
t = cfg.get('mysql','a')
print(type(t),t)
t = cfg.get('mysqld','a')
print(type(t),t)
t = cfg.get('mysqld','port')
print(type(t),t)
t = cfg.getint('mysqld','port',fallback=3306) #return int(get())
print(type(t),t)
t = bool(cfg.get('mysqld','a'))
print(type(t),t)
t = cfg.get('mysql','b',fallback='123')
print(type(t),t)

cfg.set('mysqld','a','100') #内存中

if cfg.has_section('test'):
    cfg.remove_section("test") #本section所有options全部删除

cfg.add_section('test')
print(cfg['mysql'])
cfg['test']['t1'] = '1000'
cfg['test']['t2'] = str([1,2,3])
t = cfg['test']['t2']
print(type(t),t)
print(cfg.get('test','t2'))

cfg['test'] = {'t3':'abc'}
print(cfg.options('test')) #

with open('t.ini','w') as f:
    cfg.write(f)

print(cfg._sections)
for k,v in cfg._sections.items():
    print(k,v)

序列化与反序列化

  • 需要设计一套协议,按某种规则,把内存中数据保存到文件中。文件是一个字节序列,所以必须把数据转换成字节序列,输出到文件,即序列化
  • 反之,从文件的字节序列恢复到内存并且还是原来的类型,就是反序列化

定义

  • serialization:序列化
    将内存中对象存储下来,把它们变成一个个字节 --> 二进制

  • deserialization:反序列化
    将文件中的一个个字节恢复成内存中的对象 <-- 二进制

  • 序列化保存到文件就是持久化。

  • 可以将数据序列化后持久化,或者网络传输;也可以将从文件中或者网络接收到的字节序列反序列化。

  • python提供了pickle库

Pickle库

  • dumps:对象序列化为bytes对象
  • dump:对象序列化到文件对象,就是存入文件
  • loads:从bytes对象反序列化
  • load:对象反序列化,从文件读取数据
import pickle

filename = 'c:/ser'

i = 99
c = 'c'
l = list('123')
d = {'a':1,'b':'abc','c':[1,2,3]}

#序列化
with open(filename,'wb') as f:
    pickle.dump(i,f)
    pickle.dump(c,f)
    pickle.dump(l,f)
    pickle.dump(d,f)

#反序列化
with open(filename,'rb') as f:
    print(f.read(),f.seek(0))
    for i in range(4):
        x = pickle.load(f)
        print(x,type(x))
#对象序列化
import pickle

class AAA:
    tttt = 'ABC' #类属性
    def show(self): #def 方法
        print("aabbcc")
        
a1 = AAA() #实例化 得到了一个AAA类型的实例 a1是引用类型

#序列化
ser = pickle.dumps(a1) #bytes
print('ser = {}'.format(ser)) #没有序列化他们 为什么可以打印出他们?

#with open('c:/ser','wb') as f:
#    f.write(ser)

obj = pickle.loads(ser)
print(type(obj)) #返回的是类型 AAA
print(obj) #AAA object对象实例,我在内存中什么位置
print(obj.tttt)
obj.show()
----------------------------------------
ser = b'\x80\x03c__main__\nAAA\nq\x00)\x81q\x01.'
<class '__main__.AAA'>
<__main__.AAA object at 0x000001F5EAE43588>
ABC
aabbcc
  • 上例中使用连续AAA、ABC、abc等字符串就是为了在二进制文件中能容易地发现他们
  • 上例中其实就是保存了一个类名,因为所有的其他东西都是由类定义,是不变的,所以只序列化一个AAA类名,反序列化时找到类就可以恢复一个对象
import pickle

#对象序列化
class AAA:
    tttt = 'ABC'
    def __init__(self): #初始化方法
        print('init~~~~')
        self.cccc = 'AABBCC' #实例的属性,每一个实例都不同      
        
a1 = AAA() #实例化 创建AAA类的对象 会调用__init___ 

#序列化
ser = pickle.dumps(a1) #bytes
print('ser = {}'.format(ser)) #没有序列化他们 为什么可以打印出他们? 

#反序列化
obj = pickle.loads(ser)
print(type(obj)) #返回的是类型 AAA
print(obj) #AAA object对象实例,我在内存中什么位置
print(obj.tttt) #ABC
print(obj.cccc) #AABBCC
  • 上例中除了必须保存的AAA,还序列化了cccc和AABBCC,因为这是每个对象自己的属性,每一个对象是不一样的,所以这些数据需要序列化。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值