Python高级与正则表达式 1.Python迭代器迭代器Iterator是 Python 中的一种对象用于在数据集合中逐个访问元素而不需要暴露数据集合的底层实现。它提供了一种遍历元素的标准方式适用于任何支持迭代的数据集合如列表元组等range就是一个迭代器迭代器是一个实现了_ _iter_ _ 和 _ _next_ _方法的对象使得可以逐步遍历它的元素特点手动管理需要显示地实现 _ _iter_ _和 _ _next_ _方法状态管理迭代器需要自己管理迭代的状态属性包括当前位置和结束条件内存使用内存使用取决于迭代器的实现通常是惰性计算按需生成数据1.1 创建迭代器通过给类添加_ _iter_ _ 和 _ _next_ _方法便可以定义一个迭代器类#定义一个迭代器类 class MyIterator(object): 1. 通过__init__魔法方法初始化属性指定范围 def __init__(self, start, end): self.current start #当前值默认为开始值 self.end end #结束值 #2. 通过重写__iter__魔法方法返回当前对象即迭代器对象 def __iter__(self): return self #3. 通过重写__next__魔法方法返回当前值并更新当前值 def __next__(self): #3.1 判断当前值范围是否合法 if self.current self.end : raise StopIteration #3.2 若当前值合法返回当前值并更新 value self.current self.current 1 return value注意迭代器只能遍历一次1.2 使用迭代器1.2.1 for循环#1. 实例化迭代器对象 my_iter MyIterator(1, 10) #2. 使用for循环遍历迭代器对象 for num in my_iter: #1 2 3 4 5 6 7 8 9 10 print(num)1.2.2 next函数print(next(my_generator)) #1 print(next(my_generator)) #2 print(next(my_generator)) #3nextiterator, default函数的使用iterator迭代器对象default可选迭代器耗尽时返回这个默认值作用接收迭代器取出下一个元素元素耗尽默认抛出 StopIteration如果指定 default 参数则返回 default 不再抛异常。#定义一个迭代器 class MyIterator(object): def __init__(self, start, end): self.current start self.end end def __iter__(self): return self def __next__(self): if self.current self.end : raise StopIteration value self.current self.current 1 return value #使用迭代器 my_iter2 MyIterator(11, 13) print(next(my_iter2, 结束了)) print(next(my_iter2, 结束了)) print(next(my_iter2, 结束了))结果如下小结2.Python生成器生成器根据规则循环生成数据当条件不成立时则生成数据结束。即数据不是一次性全部生成出来的而是使用一个再生成一个可以节约大量的内存目的2.1 创建生成器的方式2.1.1 生成器推导式my_generator (i for i in range(10)) print(type(my_generator)) # class generator通俗来讲其实就是与列表推导式集合推导式类似的元组推导式不过一般来讲没有元组推导式这个概念2.1.2 yield关键字只要在 def 函数里面看到有 yield 关键字那么就是生成器#1. 定义函数存储到生成器中并返回 def my_generator(): #1.1 循环 for i in range(1,11): #1.2 使用yield关键字创建生成器 #yield在这里做了三件事1.创建生成器对象 2.把值存储到生成器中 3.返回生成器 yield i #2. 调用函数获取生成器对象 gen my_generator() print(type(gen)) # class generator for i in gen: print(i)2.2 从生成器中获取元素2.2.1 for循环for num in my_generator: print(num)2.2.2 next函数print(next(my_generator)) #1 print(next(my_generator)) #2 print(next(my_generator)) #32.3 案例实现案例基于传入的数据歌词创建生成器生成批次歌词需求基于文件中周杰伦的歌词创建生成器根据传入的歌词条数生成歌词批次import math #定义一个歌词生成器 def lyric_generator(batch_size): 自定义的歌词批量生成器 :param batch_size: 每批次的歌词行数 :return: 每批次的歌词 #1. 获取歌词文件中的所有数据以行为单位 with open(./Data/周杰伦歌词.txt, r, encoding utf-8) as f: lines f.readlines() #2. 计算总批次 total_batches math.ceil(len(lines) / batch_size) #向上取整 #3. 循环获取每批次的歌词 for i in range(total_batches): #3.1 创建歌词生成器每次返回一个批次的歌词 yield lines[i*batch_size:(i1)*batch_size] if __name__ __main__: #调用生成器函数获取生成器对象 gen lyric_generator(3) #遍历生成器对象获取每批次的歌词 for i in gen: print(i)2.4 小结2.5 生成器与迭代器对比1.实现方式迭代器需要实现 iter() 和 next() 方法手动管理迭代状态生成器通过yield 关键字简化实现自动管理迭代状态2.代码复杂度迭代器通常需要更多的代码来管理状态和迭代逻辑生成器代码更简洁更容易理解和维护3.性能与内存迭代器性能和内存使用取决于实现通常也是惰性计算生成器由于使用了 yield内存使用和性能优化自动管理适合处理大数据或流数据4.使用场景迭代器适合需要对迭代过程进行高度控制或者需要自定义复杂的迭代逻辑时使用生成器适合需要简洁地生成序列数据尤其是在处理大数据或需要按需生成数据时能够节省内存和提高性能注意生成器本质上就是一种特殊的迭代器3.property属性方法属性化property属性负责把一个函数方法当作属性来用这样可以简化代码使用3.1 定义 property 属性定义 property 属性有两种方式装饰器方式类属性方式3.1.1 装饰器方式class Women(object): def __init__(self): self.__age 18 #获取私有属性 property def age(self): #公有获取私有属性方式 return self.__age #修改私有属性 age.setter def age(self, new_age): #公有修改私有属性方式 self.__age new_age if __name__ __main__: w1 Women() print(w1.age) #18 w1.age 20 print(w1.age) #20property修饰读取方法方法名.setter修饰修改值方法装饰器必须在 property 之后定义并且两个方法名字完全一样在此之后就可以直接使用对象.函数名来当做对象的属性使用3.1.2 类属性方式class Women(object): def __init__(self): self.__age 18 def get_age(self): return self.__age def set_age(self, new_age): self.__age new_age #类属性方式定义 property 属性 #将上述的获取值和修改值的公共方法封装为类属性 age property(get_age, set_age) if __name__ __main__: w1 Women() print(w1.age) #18 w1.age 20 print(w1.age) #20类属性 property获取值方法名设置值方法名注意使用类属性定义 property 属性时获取值方法和设置值方法必须要求不同名3.2 小结4.正则表达式正则表达式Regular Expression简称 RE正确的符合特定规则的字符串。用来描述匹配字符串中符合特定规则的字符序列。相当于一种模式匹配工具允许用户通过简洁的语法进行复杂文本的搜索匹配提取和替换工作4.1 正则表达式语法正则表达式的写法多种多样具体的语法如下注意字符串转义符的影响字符串Python 普通字符串里\ 是字符串转义符\n → 换行\t → tab\\ → 代表一个字面的 \比如如果想把 \d 传给正则引擎普通字符串必须写成 \\dr字符串关闭 Python 字符串转义获得原始字符串\ 就是普通反斜杠不再做任何转义处理补充\.取消 . 的特殊含义只表示一个普通的 .\s匹配空白即空格tab键等一个 \s 只能匹配一个空格或Tab\S匹配非空白\数字反向引用量词注意事项量词无法独立使用必须用来修饰字符量词{m,n}中间不要加空格反向引用\数字反向引用用来引用前面第 num 个捕获分组匹配到的文本1.什么是捕获分组括号 在正则里一是分组二是捕获会把括号内匹配到的内容存起来按顺序编号从 \1 开始2.反向引用的作用引用的是分组匹配到的真实文本不是分组里的正则表达式r([a-z])\1含义匹配一个小写字母后面跟和它一模一样的字母方便直接获取分组内容import re email 1975150458qq.com result re.match(r[a-z|A-Z|0-9|_]{4,20}(163|qq|126)\.com$, email) print(result.group(0) if result else 匹配失败) #获取第0组信息即整个匹配到的字符串 print(result.group(1) if result else 匹配失败) #获取第1组信息即163代码示例如下:import re s1 18809090000是我的手机号你记住了吗我的另一个手机号是18800008888两个QQ号分别是15500008888 和 13809091293821邮箱为python666163.com,你记住了吗 #正则表达式 print(re.findall(r188.*,s1)) # .匹配任意字符*匹配其前面字符0次或多次 print(re.findall(r188.?,s1)) # .匹配任意字符?匹配其前面字符至多1次 print(re.findall(r188.,s1)) # .匹配任意字符匹配其前面字符至少1次 print(re.findall(r188\d{8},s1)) # \d匹配任意数字{8}匹配其前面字符8次 print(re.findall(r155\d{6,10},s1)) # \d匹配任意数字{6,10}匹配其前面字符6到10次 print(re.findall(r155\d{6,},s1)) # \d匹配任意数字{6,}匹配其前面字符6次或更多 print(re.findall(r1[38]\d{8},s1)) # 1开头,第2位是3或8,\d匹配任意数字{8}匹配其前面字符8次 print(re.findall(r1[^38]\d{8},s1)) # 1开头,第2位是{3,8}以外的数字,\d匹配任意数字{8}匹配其前面字符8次 print(re.findall(r1[3-9]\d{8},s1)) # 1开头,第2位是3-9之间的数字,\d匹配任意数字{8}匹配其前面字符8次 print(re.findall(r^1[3-9]\d{9},s1)) # ^匹配字符串开头为1,第2位是3-9之间的数字,\d匹配任意数字{9}匹配其前面字符9次 print(re.findall(r^1[3-9]\d{9}$,s1)) # ^匹配字符串开头为1,第2位是3-9之间的数字,\d匹配任意数字{9}匹配其前面字符9次,$匹配字符串结尾 print(re.findall(r\w\w\.\w,s1,)) #\w匹配任何单词字符(a-z,A-Z,0-9,_,其他语言字符),\.转义字符只表示匹配. print(re.findall(r\w\w\.\w,s1,re.ASCII)) #re.ASCII限制只匹配ASCII中字符 s2 现在的时间是2026-08-18 19:06:10,今天的天气还可以,气温是28度 print(re.findall(r\d{4}-\d{2}-\d{2},s2)) print(re.findall(r(\d{4})-(\d{2})-(\d{2}),s2)) #封装元组4.2 正则表达式操作函数作用返回值re.matchpatstr只从字符串开头匹配第一个Match 对象 / Nonere.searchpatstr从任意位置开始匹配第一个Match 对象 / Nonere.findallpatstr找出全部匹配结果list 列表re.subpatstr2str1 将字符串str1中匹配到的内容全部替换为str2字符串 strpat正则表达式str文本字符串4.2.1 字符串match匹配1.导入模块import re2.正则表达式与要检验的字符串进行匹配从开头result re.match(正则表达式, 要校验的字符串)3.获取匹配结果if result: print(result.group()) else: print(匹配失败)相关代码如下import re s1 18809090000是我的手机号你记住了吗我的另一个手机号是18800008888两个QQ号分别是155998992 和 18809091293821你记住了吗 result re.match(r1[3-9]\d{9},s2) #match--从字符串的开头开始匹配(只会匹配第一个匹配项)返回 match对象/None if result: print(result.group()) #获取到匹配的结果 print(result.span()) #匹配项的索引 print(result.start()) #匹配项的开始索引 print(result.end()) #匹配项的结束索引 else: print(匹配失败)4.2.2 字符串search匹配1.导入模块import re2.正则表达式与要检验的字符串进行匹配从任意位置result re.search(正则表达式, 要校验的字符串)3.获取匹配结果if result: print(result.group()) else: print(匹配失败)相关代码如下import re s2 我的手机号是18809090000你记住了吗我的另一个手机号是18800008888两个QQ号分别是155998992 和 18809091293821你记住了吗 #search--从字符串的任意位置开始匹配(只会匹配第一个匹配项),返回match对象 result re.search(r1[3-9]\d{9},s2) if result: print(result.group()) #获取到匹配的结果 print(result.span()) #匹配项的索引 print(result.start()) #匹配项的开始索引 print(result.end()) #匹配项的结束索引 else: print(匹配失败)4.2.3 字符串findall匹配1.导入模块import re2.正则表达式与要检验的字符串进行匹配result re.findall(正则表达式, 要校验的字符串)3.获取匹配结果print(result)相关代码如下import re s2 我的手机号是18809090000你记住了吗我的另一个手机号是18800008888两个QQ号分别是155998992 和 18809091293821你记住了吗 #findall--返回所有匹配项的列表,返回列表 result re.findall(r1[3-9]\d{9},s2) print(result)4.2.4 字符串compile sub替换1.导入模块import re2.正则表达式与要检验的字符串进行匹配result re.compile(正则表达式) #返回正则表达式对象 result result.sub(替换后的内容, 要被匹配和替换的字符串)3.获取替换结果print(result)新版API写法result re.sub(正则表达式, 替换后的内容, 要被匹配和替换的字符串)4.3 正则表达式案例案例1匹配 qq195737 这样的数据从中提取 “qq” 和 qq号码import re qq_number qq:1319831324 result re.match(r(qq):(\d), qq_number) print(result.group(1,2) if result else 匹配失败) #结果(qq, 1319831324)案例2校验 html 标签import re html headtitle示例标题/title/head /html html_s htmlheadtitle示例标题/title/head/html #方式1最传统方式 result re.match(r[a-z|A-Z]{1,5}[a-z|A-Z]{1,5}[a-z|A-Z]{1,5}.*/[a-z|A-Z]{1,5}/[a-z|A-Z]{1,5}/[a-z|A-Z]{1,5}, html_s) print(result.group() if result else 匹配失败) #方式2:使用反向引用 result re.match(r([a-z|A-Z]{1,5})([a-z|A-Z]{1,5})([a-z|A-Z]{1,5}).*/\3/\2/\1, html_s) print(result.group() if result else 匹配失败) #方式3:使用反向引用同时给引用命名 result re.match(r(?Pfirst[a-z|A-Z]{1,5})(?Psecond[a-z|A-Z]{1,5})(?Pthird[a-z|A-Z]{1,5}).*/(?Pthird)/(?Psecond)/(?Pfirst), html_s) print(result.group() if result else 匹配失败)反向引用的命名设置分组P分组名分组内表达式)引用分组P分组名