闭包: 能够访问其他函数内部变量的函数就叫做闭包,弱数据类型的语言特有的现象 闭包最大的特点就是将局部变量全局化,但导致了局部变量无法及时释放,常驻内存,内存的占有比较高,只是此时局部变量作用域比较小,代码整合时可以防止变量覆盖 闭包优化了变量,原来需要类对象完成的工作,闭包也可以完成
#这是一个闭包:inner函数能够访问outer函数内部变量a #引用传递是将函数内存地址赋给变量,函数调用是将函数返回值赋给变量 def outer(): a = 10 print("这是外部函数") def inner(): print(a) print("这是内部函数") return inner #outer函数返回的是一个函数,所以此时a指向inner函数 a = outer() #函数调用是将函数返回值(return inner)赋给变量 #print(a) #<function outer.<locals>.inner at 0x000001918F667598> #调用a函数,相当于调用inner函数 a() #outer()() #此时也可以调用inner函数装饰器:就是在运行原来功能基础上,加上一些其它功能 装饰器功能:引入日志、函数执行时间统计、执行函数前预备处理、执行函数后清理功能、权限校验、异常处理、缓存 OCP原则(open close protocol):写代码要遵循开放封闭原则 设计模式的出现:golf提出了23种设计模式—装饰者设计模式
#闭包函数中的参数fn就是我们要装饰的对象,只需要加@logining就可以使用闭包函数logining()对原来的login()与reg()函数进行装饰 def logining(fn): def inner(): print("正在加入日志") fn() print("日志已经加入") return inner #此处返回inner函数,并且@logining已经将login函数替换为inner函数,下面调用login函数时返回的是inner函数 @logining #执行@logining时logining函数中的fn就是login函数 def login(): print("登录") @logining def reg(): print("注册") login() reg()1、被装饰的函数无参数
#装饰器没有打破OCP原则,而是将需要加入的功能正常的添加进去,可用于重构代码 #装饰器可以装饰多个函数 #被装饰函数无参数 def logining(fn): def inner(): print("开始记录日志……") fn() print("日志记录完成……") return inner def check(fn): def inner(): print("开始数据校验……") fn() return inner @logining @check def login(): print("登录") if __name__ == '__main__': login() 运行结果: 开始记录日志…… 开始数据校验…… 登录 日志记录完成……2、被装饰的函数存在参数,则参数在装饰器内部的函数中传递
#被装饰函数有参数 def logining(fn): #如果被装饰的函数存在参数,则参数在装饰器内部的函数中传递 def inner(username,password,*arg,**kwarg): print("开始记录日志……") fn(username,password,*arg,**kwarg) print("日志记录完成……") return inner def check(fn): def inner(username,password,*arg,**kwarg): print("开始数据校验……") fn(username,password,*arg,**kwarg) return inner @logining @check def login(username,password,*arg,**kwarg): print(username + "使用密码登录,密码是" + password) print("登录") if __name__ == '__main__': UserName = "zhang" PassWord = "123" login(UserName,PassWord)3、被装饰的函数存在返回值,则需要在内部函数调用原函数时返回
#如果被装饰的函数存在返回值,则需要在内部函数调用原函数时返回 def logining(fn): #如果被装饰的函数存在参数,则参数在装饰器内部的函数中传递 def inner(username,password,*arg,**kwarg): print("开始记录日志……") f = fn(username,password,*arg,**kwarg) print("日志记录完成……") return f return inner def check(fn): def inner(username,password,*arg,**kwarg): print("开始数据校验……") return fn(username,password,*arg,**kwarg) return inner @logining @check def login(username,password,*arg,**kwarg): print(username + "使用密码登录,密码是" + password) print("登录") return True if __name__ == '__main__': UserName = "zhang" PassWord = "123" login(UserName,PassWord)偏函数:
#偏函数的使用 from functools import partial def print_msg(msg,type = 1): if type == 1: for x in msg: print(x) elif type == 2: for k,v in msg.items(): print(k,v) elif type == 3: for x in msg: print(x) print_msg("you are dog?") #type不写默认为1 print_msg({"k1":25,"k2":100,"k3":150},type = 2) print_msg([1,2,3,4,5,6],type = 3) #此时print_dict函数就是print_msg函数,但是print_dict的type值已经固定为2 print_dict = partial(print_msg,type = 2) print_dict({"k1":25,"k2":100,"k3":150}) #等价于print_msg({"k1":25,"k2":100,"k3":150},type = 2) print(print_dict) #functools.partial(<function print_msg at 0x000002093A991E18>, type=2)python—正则表达式 正则表达式也叫作匹配模式,它是由一组具有特定含义的字符串组成,通常用匹配和替换文本 python中对于正则的支持—re方法
>>> import re >>> dir(re) ['A', 'ASCII', 'DEBUG', 'DOTALL', 'I', 'IGNORECASE', 'L', 'LOCALE', 'M', 'MULTILINE', 'RegexFlag', 'S', 'Scanner', 'T', 'TEMPLATE', 'U', 'UNICODE', 'VERBOSE', 'X', '_MAXCACHE', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '__version__', '_alphanum_bytes', '_alphanum_str', '_cache', '_compile', '_compile_repl', '_expand', '_locale', '_pattern_type', '_pickle', '_subx', 'compile', 'copyreg', 'enum', 'error', 'escape', 'findall', 'finditer', 'fullmatch', 'functools', 'match', 'purge', 'search', 'split', 'sre_compile', 'sre_parse', 'sub', 'subn', 'template']常用方法:
findall() #查找所有匹配的内容,返回的结果为列表 finditer() #查找所有匹配的内容,返回的结果为一个迭代器 search #只查找一次 match() #从头匹配一个正则表达式 sub #用来替换匹配的内容,使其变为期望出现的内容 compile #先写规则,再匹配数据,注意compile存在第二个参数,当我们填入第二个参数是,会相应修改正则规则正则的使用: 元字符与反义符
1、.:只有换行符(\n)不能匹配,其他均可匹配 2、\d:匹配任意数字,等价于[0123456789]等价于[0-9],\D匹配任意非数字 3、\w:匹配有效符号(大小写、数字、_),python中还可以匹配中文;\W跟\w正好相反匹配特殊字符 4、\s:匹配空白符,\S匹配任意非空白符 5、[]:表示范围,[0-9]所有数字[a-z]小写、[A-Z]大写、[a-zA-Z]大小写、[0-9a-zA-Z_]所有有效字符 6、^:表示以……开头 7、*:表示0-多 8、$:表示以……结尾 9、: 10、\b:匹配单词的开始或结束 11、[^]:表示不能包含[]范围内字符 12、+:匹配1-多 13、?:匹配0或1---没有或者有一个 14、{m}:表示有m位;{m,}:表示至少m位;{m,n}表示[m,n]区间内位,至少m位,最多n位match的使用
>>> s = "you are a dog?" >>> re.match("you",s) <_sre.SRE_Match object; span=(0, 3), match='you'> >>> res = re.match("you",s) >>> res.group() 'you' >>> res <_sre.SRE_Match object; span=(0, 3), match='you'> >>> re.match(r".","2") <_sre.SRE_Match object; span=(0, 1), match='2'> >>> re.match(r".","a") <_sre.SRE_Match object; span=(0, 1), match='a'> >>> re.match(r".","%") <_sre.SRE_Match object; span=(0, 1), match='%'> >>> re.match(r".","\t") <_sre.SRE_Match object; span=(0, 1), match='\t'> >>> re.match(r".","*") <_sre.SRE_Match object; span=(0, 1), match='*'> >>> re.match(r"\d","3") <_sre.SRE_Match object; span=(0, 1), match='3'> >>> re.match(r"\d","5") <_sre.SRE_Match object; span=(0, 1), match='5'> >>> re.match(r"\d","10") <_sre.SRE_Match object; span=(0, 1), match='1'> >>> re.match(r"\d\d","10") <_sre.SRE_Match object; span=(0, 2), match='10'> >>> re.match(r"[0123456789]","6") <_sre.SRE_Match object; span=(0, 1), match='6'> >>> re.match(r"[0123456789]\d\d\d","6666") <_sre.SRE_Match object; span=(0, 4), match='6666'> >>> re.match(r"\D*","!@#$%^&*()_+") <_sre.SRE_Match object; span=(0, 12), match='!@#$%^&*()_+'> >>> re.match(r"\D*","6732skfh") <_sre.SRE_Match object; span=(0, 0), match=''> >>> re.match(r"\D","3") >>> re.match(r"\w","10") <_sre.SRE_Match object; span=(0, 1), match='1'> >>> re.match(r"\w\w","10") <_sre.SRE_Match object; span=(0, 2), match='10'> >>> re.match(r"\w","2") <_sre.SRE_Match object; span=(0, 1), match='2'> >>> re.match(r"\w","a") <_sre.SRE_Match object; span=(0, 1), match='a'> >>> re.match(r"\w","A") <_sre.SRE_Match object; span=(0, 1), match='A'> >>> re.match(r"\w","*") >>> re.match(r"\w","&") >>> re.match(r"\w","$") >>> re.match(r"\w","_") <_sre.SRE_Match object; span=(0, 1), match='_'> >>> re.match(r"\w\w","中文") <_sre.SRE_Match object; span=(0, 2), match='中文'> >>> re.match(r"\W","0") >>> re.match(r"\W","a") >>> re.match(r"\W","+") <_sre.SRE_Match object; span=(0, 1), match='+'> >>> re.match(r"\W*","!@#$%^&*()") #表示匹配特殊字符 <_sre.SRE_Match object; span=(0, 10), match='!@#$%^&*()'> >>> re.match(r"\W*","!@#$%^&*()_+") <_sre.SRE_Match object; span=(0, 10), match='!@#$%^&*()'> >>> re.match(r"\s"," ") #表示匹配空格符 <_sre.SRE_Match object; span=(0, 1), match=' '> >>> re.match(r"\s","\t") <_sre.SRE_Match object; span=(0, 1), match='\t'> >>> re.match(r"\S","\t") >>> re.match(r"\S"," ") >>> re.match(r"[0-9a-zA-Z_]","2") <_sre.SRE_Match object; span=(0, 1), match='2'> >>> re.match(r"[0-9a-zA-Z_]","a") <_sre.SRE_Match object; span=(0, 1), match='a'> >>> re.match(r"[0-9a-zA-Z_]","D") <_sre.SRE_Match object; span=(0, 1), match='D'> >>> re.match(r"[0-9a-zA-Z_]","_") <_sre.SRE_Match object; span=(0, 1), match='_'> >>> re.match(r"^4","445555") #表示匹配以4开头 <_sre.SRE_Match object; span=(0, 1), match='4'> >>> re.match(r".*a$","dajfojflfa") #表示匹配以a结尾的字符串 <_sre.SRE_Match object; span=(0, 10), match='dajfojflfa'> >>> re.match(r"^4.*5$","445555") <_sre.SRE_Match object; span=(0, 6), match='445555'> >>> re.match(r"[^ab].*","akfjkajfjiel") #表示不匹配以a或b开头的字符串 >>> re.match(r"[^ab].*","bkfjkajfjiel") >>> re.match(r"[^ab].*","dkfjkajfjiel") <_sre.SRE_Match object; span=(0, 12), match='dkfjkajfjiel'> >>> re.match(r"\d+","5211314") #表示匹配1-多 <_sre.SRE_Match object; span=(0, 7), match='5211314'> >>> re.match(r"\d+","") >>> re.match(r"\d*","") #表示匹配0-多 <_sre.SRE_Match object; span=(0, 0), match=''> >>> re.match(r"\d?","") #表示匹配0或1 <_sre.SRE_Match object; span=(0, 0), match=''> >>> re.match(r"\d?"," ") <_sre.SRE_Match object; span=(0, 0), match=''> >>> re.match(r"\d?","1") <_sre.SRE_Match object; span=(0, 1), match='1'> >>> re.match(r"^1[3-9]\d{9}","18220486109") #表示以1开头,第二位为3-9,之后9位的电话号码 <_sre.SRE_Match object; span=(0, 11), match='18220486109'> >>> re.match(r"^1[3-9]\d{5,}","18220486109") #表示以1开头,第二位为3-9,之后最少5位的电话号码 <_sre.SRE_Match object; span=(0, 11), match='18220486109'> >>> re.match(r"^1[3-9]\d{5,10}","18220486109") #表示以1开头,第二位为3-9,之后至少5位最多10位的电话号码 <_sre.SRE_Match object; span=(0, 11), match='18220486109'> >>> re.match(r"^1[3-9]\d{5,8}","18220486109") #表示以1开头,第二位为3-9,之后至少5位最多8位的电话号码 <_sre.SRE_Match object; span=(0, 10), match='1822048610'> >>> re.match(r"^1[3-9]\d{1,5}","18220486109") #表示以1开头,第二位为3-9,之后至少1位最多5位的电话号码 <_sre.SRE_Match object; span=(0, 7), match='1822048'>findall的使用
>>> re.findall(r"\d{4}","今年是2019年,我16岁很帅,过两年18岁会更帅") ['2019'] >>> re.findall(r"\d{3}","今年是2019年,我16岁很帅,过两年18岁会更帅") ['201'] >>> re.findall(r"\d{2}","今年是2019年,我16岁很帅,过两年18岁会更帅") ['20', '19', '16', '18'] >>> re.findall(r"\d{1}","今年是2019年,我16岁很帅,过两年18岁会更帅") ['2', '0', '1', '9', '1', '6', '1', '8'] >>> re.findall(r"\d+","今年是2019年,我16岁很帅,过两年18岁会更帅") ['2019', '16', '18']匹配HTML标签: r"<\w>.*</\w+>" 但是此时有问题,因为两个\w匹配到的标签可能不一致,所以需要使用分组引用解决该问题 **分组引用:**在正则中,若将正则的表达式使用()包裹起来,使其可以达到二次识别的作用,除此之外还可以作为正则的一部分进行下一次匹配 1、分组在表达式内部使用:使用\n来引用第n个()内的内容
r"<(\w)>.*</\1>" #此处的\1表示使用()包裹起来的匹配到的内容2、分组在表达式外部使用:分组做二次筛选,对获取的匹配结果re.match(r".(.).*",content),即res进行group筛选—res.group(1),此时匹配第一个()内的内容
>>> content = """ ... <div><ul><li><a>此处是内容</a></li></ul></div>""" >>> content '\n<div><ul><li><a>此处是内容</a></li></ul></div>' >>> re.findall(r"<a>.*</a>",content) ['<a>此处是内容</a>'] >>> re.findall(r"<a>(.*)</a>",content) ['此处是内容'] >>> re.match(r"<a>(.*)</a>",content) >>> content = re.sub("\n","",content) >>> re.match(r".*<a>(.*)</a>.*",content) <_sre.SRE_Match object; span=(0, 41), match='<div><ul><li><a>此处是内容</a></li></ul></div>'> >>> res = re.match(r".*<a>(.*)</a>.*",content) >>> res.group(1) '此处是内容finditer的使用
>>> s = re.finditer(r"<td>(.*?)</td>",content) >>> for x in s: ... print(x.group()) ... <td>此处是内容</td> <td>此处也是内容</td> <td>此处还是内容</td> <td>此处依旧是内容</td> <td>此处是最后的内容</td>sub的使用
>>> content = "16岁的我超级帅,18岁的我会更加帅" >>> re.sub("\d+","*",content) '*岁的我超级帅,*岁的我会更加帅' >>> content '<table><tr><td>此处是内容</td><td>此处也是内容</td><td>此处还是内容</td><td>此处依旧是内容</td><td>此处是最后的内容</td></tr></table>' >>> re.sub("</?.*?>","",content) '此处是内容此处也是内容此处还是内容此处依旧是内容此处是最后的内容'search的使用
>>> content = "16岁的我超级帅,18岁的我会更加帅" >>> re.search("\d+",content) <_sre.SRE_Match object; span=(0, 2), match='16'> >>> res = re.search("\d+",content) >>> res.group() '16'compile的使用
>>> content = "16岁的我超级帅,18岁的我会更加帅" >>> p = re.compile("\d+") #先写规则 >>> dir(p) ['__class__', '__copy__', '__deepcopy__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'findall', 'finditer', 'flags', 'fullmatch', 'groupindex', 'groups', 'match', 'pattern', 'scanner', 'search', 'split', 'sub', 'subn'] >>> p.findall(content) #使用各种操作匹配数据 ['16', '18'] >>> p = re.compile("a") #指定规则 >>> s = "akdhlakiwfafkahljlajfliajlajfilajs" >>> p.findall(s) #匹配数据 ['a', 'a', 'a', 'a', 'a', 'a', 'a', 'a'] >>> s = "akdhlakiwAfafkahljlajAfliajlajAfilajs" >>> p.findall(s) #加入A之后查不到A ['a', 'a', 'a', 'a', 'a', 'a', 'a', 'a'] >>> p = re.compile("a",re.I) #改变参数,使其忽视大小写(默认建议不要改动) >>> p.findall(s) ['a', 'a', 'A', 'a', 'a', 'a', 'A', 'a', 'a', 'A', 'a']正则里面匹配路径(需要使用四个\,建议使用r’\a’,此时双引号变为单引号):因为正则中的\有特殊含义,python中的\也有特殊含义,则需要两个\进行转义
>>> path = "c:\\a\\b\\c.txt" >>> re.match("c:\\\\a\\\\b\\\\c.txt",path) <_sre.SRE_Match object; span=(0, 12), match='c:\\a\\b\\c.txt'> 但是python的正则中加上r之后也可以进行匹配(如下) >>> re.match(r'c:\\a\\b\\c.txt',path) <_sre.SRE_Match object; span=(0, 12), match='c:\\a\\b\\c.txt'>练习1: 匹配邮箱地址,且@之前有4到20位字符,如8461414_abc@abc.com
>>> re.match(r"\w{4,20}@\D*","8461414_abc@abc.com") <_sre.SRE_Match object; span=(0, 19), match='8461414_abc@abc.com'>练习2: 匹配内容
<div><ul><li><a>此处是内容</a></li></ul><ul><li><a>此处也是内容</a></li></ul></div> <table><tr><td>此处是内容</td><td>此处也是内容</td><td>此处还是内容</td><td>此处依旧是内容</td><td>此处是最后的内容</td></tr></table>贪婪模式与非贪婪模式: 贪婪模式:尽可能多的匹配,直到遇到换行(\n)或者不符合匹配条件 非贪婪模式(懒惰模式):正则表达式中,符合条件的前提下,会尽可能少的匹配 一般在+ * ?再加入一个?即可将贪婪模式变为非贪婪模式
>>> content = "<div><ul><li><a>此处是内容</a></li></ul><ul><li><a>此处也是内容</a></li></ul></div>" >>> re.findall(r"<a>(.*?)</a>",content) ['此处是内容', '此处也是内容'] >>> content '<table><tr><td>此处是内容</td><td>此处也是内容</td><td>此处还是内容</td><td>此处依旧是内容</td><td>此处是最后的内容</td></tr></table>' >>> re.findall(r"<td>(.*?)</td>",content) ['此处是内容', '此处也是内容', '此处还是内容', '此处依旧是内容', '此处是最后的内容']作者:苏小酱
