Python进阶07-高级语法

2024-08-31 09:20
文章标签 python 进阶 语法 高级 07

本文主要是介绍Python进阶07-高级语法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

零、文章目录

Python进阶07-高级语法

1、with语句

(1)文件操作
  • 文件使用完后必须关闭,因为文件对象会占用操作系统的资源,并且操作系统同一时间能打开的文件数量也是有限的
# 第一步:打开文件
f = open('python.txt', 'w', encoding='utf-8')
# 第二步:写入内容
f.write('人生苦短,我学Python!')
# 第三步:关闭文件
f.close()
(2)文件操作异常
  • 由于文件读写时有可能产生IOError,一旦出错,后面的f.close()就不会调用。
# 第一步:打开文件
f = open('python.txt', 'r', encoding='utf-8')
# 第二步:写入内容
f.write('人生苦短,我学Python!')  # 出现了异常,not writable,如果此代码出错,会导致下方代码无法执行
# 第三步:关闭文件
f.close()
(3)try…catch…finally解决异常情况
  • 这种方法虽然代码运行良好,但是缺点就是代码过于冗长,并且需要添加try-except-finally语句,不是很方便,也容易忘记。,
try:# 第一步:打开文件f = open('python.txt', 'r', encoding='utf-8')# 第二步:写入内容f.write('人生苦短,我学Python!')
except:# 第一步:打开文件f = open('python.txt', 'w', encoding='utf-8')# 第二步:写入内容f.write('人生苦短,我学Python!')
finally:f.close()
(4)with语句优化代码
  • Python提供了 with 语句的这种写法,既简单又安全,并且 with 语句执行完成以后自动调用关闭文件操作,即使出现异常也会自动调用关闭文件操作。
'''
with语句:上下文管理器 => with语句通常有两部分操作(上文、下文)
如果是文件操作 => 上文管理器负责打开文件,下文管理器负责关闭文件,而且关闭操作是自动的,即使遇到了异常也会自动关闭
with open('python.txt', 'w') as f:content = f.read()print(content)# 当文件执行结束,with语句会自动关闭刚才产生的f文件对象
'''
with open('python.txt', 'r', encoding='utf-8') as f:content = f.read()print(content)

2、yield生成器

(1)生成器是什么
  • 根据程序员制定的规则循环生成数据,当条件不成立时则生成数据结束。数据不是一次性全部生成出来,而是使用一个,再生成一个,可以节约大量的内存
  • 创建生成器的方式:
    • ① 生成器推导式
    • ② yield 关键字
(2)生成器推导式
  • 推导式,用于简化循环代码
'''
推导式:把一个有规律的数据推导为列表结构(有规律),主要作用:用于简化for...in循环代码
'''
list1 = []
for i in range(10):list1.append(i)
print(list1)# 把以上代码更改为推导式的形式
list2 = [i for i in range(10)]
print(list2)
  • 生成器相关函数:
    • next:函数获取生成器中的下一个值
    • for:循环遍历生成器中的每一个值
'''
基本语法:
生成器对象 = (推导式代码 => 列表推导式怎么写的,生成器里面的代码也可以同样书写)
举个栗子:创建一个生成器对象,同时保存0-9一共10个元素
注意:虽然生成器的语法和元组推导式感觉很像,但是要特别注意Python中并没有元组推导式,其返回的结果一个generator生成器对象
在生成器中有一个方法,叫做next()方法,其主要功能就是获取生成器中的下一个元素
还有一个特别注意点:生成器中存储的和列表推导式存储的结果有所不同
列表推导式存储的是具体的数据0-9
生成器中存储的并不是具体的数据,而是数据的生成规则,每次next()方法,系统会自动根据生成器的生成规则生成一个元素
这样做的好处就是可以节省大量的空间(真正做到随用随取)
'''
generator = (i for i in range(10))   # (生成元素的规则,第一次打印生成一个0,第二次打印生成一个1)
print(generator)  # generator object# 如何获取生成器中的元素,我们可以基于next()方法调用生成器中的规则,打印元素
result = next(generator)
print(result)result = next(generator)
print(result)result = next(generator)
print(result)# 还可以基于for循环遍历generator生成器对象,获取生成器中的所有数据
for i in generator:print(i)
(3)为什么使用推导式
  • 可以大量节省内存
'''
案例:使用列表推导式方式以及生成器推导式方式创建一组数据,一共有10000000万条数据,从0开始,针对这个列表生成一个新元素
新元素中包含10000000万条数据,每一个值是列表中每个值的平方。
[0, 1, 2, 3] 推导 [0, 1, 4, 9]
通过以下案例分析可知:相对于列表推导式,生成器更加节省内存空间,减少能耗!
为什么会产生以下结果?
答:因为列表推导式,列表中保存的是具体的数据而生成器对象,其对象中保存的并不是具体的数据,而是1000万条数据的生成规则,随用随取,所以其只需要少量的空间,就可以达到相同的运行结果
'''
import memory_profiler as memlist1 = list(range(10000000))print(f'运算前内存使用情况:{mem.memory_usage()}')
# list2 = [i ** 2 for i in list1]
generator = (i ** 2 for i in list1)
print(f'运算后内存使用情况:{mem.memory_usage()}')print(next(generator))
(4)yield生成器
  • 除了可以使用(推导式)方式来创建生成器对象以外,我们还可以通过函数 + yield方式来创建生成器
'''
在Python中,除了可以使用(推导式)方式来创建生成器对象以外,我们还可以通过函数 + yield方式来创建一个生成器。
这种创建方式是Python3中比较推荐的一种使用方式。
基本语法:
def 函数名称():...yield 值...
'''
def generator(n):for i in range(n):print('开始生成数据')yield i  # 暂时可以把yield关键字理解为return,相当于返回数据的含义 => return 0print('数据生成完成')result = generator(5)
print(result)print(next(result))
# 以上next(result),先执行了print('开始生成数据'),然后通过yield关键字返回了第一个数据0,然后函数中止执行,但是要特别注意,这里只是暂停在yield i这个位置,当我们下一次执行生成器的时候,程序会在此结束位置开始继续执行
print('-' * 40)
print(next(result))
print('-' * 40)
print(next(result))
(5)yield生成器实现斐波那契数列
  • 数学中有个著名的斐波拉契数列(Fibonacci)要求:数列中第一个数为1,第二个数为1,其后的每一个数都可由前两个数相加得到:例子:1, 1, 2, 3, 5, 8, 13, 21, 34, …
  • 现在我们使用生成器来实现这个斐波那契数列,每次取值都通过算法来生成下一个数据,生成器每次调用只生成一个数据,可以节省大量的内存。
'''
斐波那契数列:数学中的一个概念,是一组有规律的数字!
1 1 2 3 5 8 13 21 34 55 ...
规律:
隐藏了一个元素 => 0
第1个元素为1
第2个元素为1,第2个元素为1,实际上是由0 + 1 = 隐藏元素 + 第一个元素
第3个元素为2 = 1 + 1,第3个元素值 = 第2个元素值 + 第1个元素值
第4个元素为3 = 2 + 1,第4个元素值 = 第3个元素值 + 第2个元素值
刚好满足:数据量比较大,而且还要经过大量的计算 => 符合生成器的使用规则
0 1 1 2 3 5 8 13 21 34 55 ...
a变量代表,斐波那契数列中前一个元素,比如a可以代表0
b变量代表,斐波那契数列中后一个元素,比如b可以代表1
a,b是相邻的两个元素
'''
def fib(max):  # 求max位斐波那契数列 => 前max位斐波那契数列的每个值n, a, b = 0, 0, 1while n < max:yield b  # 第一次循环,弹出一个1# 想个办法,让第二次yield b,弹出一个1,第三次yield b,弹出一个2# a = 0, b = 1a, b = b, a + b# a = 1, b = 1n += 1result = fib(50)
for i in result:print(i)

3、深浅拷贝

(1)可变类型/不可变类型
  • 不可变对象:一旦创建就不可修改的对象,包括字符串、元组、数值类型(整型、浮点型)
    • 该对象所指向的内存中的值不能被改变。当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,变量再指向这个新的地址。
  • 可变对象:可以修改的对象,包括列表、字典、集合
    • 该对象所指向的内存中的值可以被改变。变量(准确的说是引用)改变后,实际上是其所指的值直接发生改变,并没有发生复制行为,也没有开辟新的地址,通俗点说就是原地改变。
(2)变量赋值原理
  • a = “python”:Python解释器干的事情
    • ① 创建变量a
    • ② 创建一个对象(分配一块内存),来存储值 ‘python’
    • ③ 将变量与对象,通过指针连接起来,从变量到对象的连接称之为引用(变量引用对象)

image-20240828155520216

(3)浅拷贝
  • 浅拷贝: 创建新对象,其内容是原对象的引用。
  • 浅拷贝之所以称为浅拷贝,是它仅仅只拷贝了一层,拷贝了最外围的对象本身,内部的元素都只是拷贝了一个引用而已

image-20240828155704060

(4)浅拷贝-可变类型

image-20240828155811430

(5)浅拷贝-不可变类型

image-20240828155904624

(6)浅拷贝总结
  • 当浅复制的值是不可变对象(字符串、元组、数值类型)时和“赋值”的情况一样,对象的id值(id()函数用于获取对象的内存地址)与浅复制原来的值相同。
  • 当浅复制的值是可变对象(列表、字典、集合)时会产生一个“不是那么独立的对象”存在。
    • 第一种情况:复制的对象中无复杂子对象,原来值的改变并不会影响浅复制的值,同时浅复制的值改变也并不会影响原来的值。原来值的id值与浅复制原来的值不同。
    • 第二种情况:复制的对象中有复杂子对象(例如列表中的一个子元素是一个列表),如果不改变其中复杂子对象,浅复制的值改变并不会影响原来的值。 但是改变原来的值中的复杂子对象的值会影响浅复制的值。
(7)深拷贝
  • 深拷贝:和浅拷贝对应,深拷贝拷贝了对象的所有元素,包括多层嵌套的元素。深拷贝出来的对象是一个全新的对象,不再与原来的对象有任何关联。所以改变原有被复制对象不会对已经复制出来的新对象产生影响。只有一种形式,copy模块中的deepcopy函数。
(8)深拷贝-可变类型

image-20240828160502832

(9)深拷贝-不可变类型
  • 不可变类型深拷贝:不可变类型进行深拷贝不会给拷贝的对象开辟新的内存空间,而只是拷贝了这个对象的引用。

image-20240828161753288

4、正则表达式

(1)正则表达式有什么用
  • 在实际开发过程中经常会有查找符合某些复杂规则的字符串的需要比如:邮箱、图片地址、手机号码等这时候想匹配或者查找符合某些规则的字符串就可以使用正则表达式了。
(2)正则表达式是什么
  • 正则表达式(regular expression):描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串、将匹配的子串做替换或者从某个串中取出符合某个条件的子串等。
    • 模式:一种特定的字符串模式,这个模式是通过一些特殊的符号组成的。
    • 某种:也可以理解为是一种模糊匹配。
      • 精准匹配:select * from blog where title=‘python’;
      • 模糊匹配:select * from blog where title like ‘%python%’;
  • 正则表达式并不是Python所特有的,在Java、PHP、Go以及JavaScript等语言中都是支持正则表达式的。
(3)正则表达式的功能
  • ① 数据验证(表单验证、如手机、邮箱、IP地址)
  • ② 数据检索(数据检索、数据抓取) => 爬虫功能
  • ③ 数据隐藏(135****6235 王先生)
  • ④ 数据过滤(论坛敏感关键词过滤)
(4)re模块的介绍
  • 在Python中需要通过正则表达式对字符串进行匹配的时候,可以使用一个re模块
  • re模块使用三步走
    • 导入re模块:import re
    • 使用match方法进行匹配操作:result = re.match(pattern正则表达式, string要匹配的字符串, flags=0)
    • 如果数据匹配成功,使用group方法来提取数据:result.group()
# 1、使用正则表达式匹配数字8
import restr1 = '13567006604'
result = re.findall('8', str1)
if result:print(result)
else:print('暂未匹配到任何数据!')# 2、查找一个字符串中是否具有数字(0-9)
str2 = 'abcdef9ghij6kl1mn'
result = re.findall('[0-9]', str2)
print(result)# 3、查找一个字符串中是否具有非数字
str3 = '12345a67b89c0'
result = re.findall('[^0-9]', str3)
print(result)
  • 正则表达式中的相关方法
    • ① re.match():匹配以正则开头的字符串信息,返回一个re对象,group()打印结果
    • ② re.search():在字符串中匹配正则表达式中的内容,没有位置限制,但是默认只能匹配第一个匹配到的结果
    • ③ re.findall():匹配字符串中所有满足正则表达式的结果,返回是一个列表类型数据
    • ④ re.finditer():匹配正则表达式中所有内容,包括分组内容,但是其返回结果是一个可迭代对象,必须使用for循环遍历,然后通过group()才能获取结果
    • ⑤ re.split():按照正则表达式匹配到的内容对字符串进行切割操作
(5)匹配单个字符

image-20240828164954671

'''
正则表达式 => ① 查什么 ② 查多少 ③ 从哪查
import re模块
要用到的知识点:match() => re.match('正则表达式', 字符串)
match只能匹配出以正则开头的内容,使用match匹配某个字符
'''
import re
# 1、匹配字符串中的第一个数字字符
str1 = '6abcdefg'
result = re.match('\d', str1)
if result:print(result.group())# 2、匹配任意某1个字符
str2 = '@abcd123'
result = re.match('.', str2)
if result:print(result.group())# 3、匹配aeiou字符中的任意某个字符
str3 = 'abcdefg'
result = re.match('[aeiou]', str3)
if result:print(result.group())# 4、匹配空白字符\s字符串
str4 = ' admin'
result = re.match('\s', str4)
if result:print(len(result.group()))# 5、字符簇取反[0-9] => [^0-9]匹配0-9以外的其他某1个字符
str5 = 'z12345'
result = re.match('[^0-9]', str5)
if result:print(result.group())# 6、匹配26个字符中的任意某个字符
str6 = 'Abc123'
result = re.match('[a-zA-Z]', str6)
if result:print(result.group())# 7、匹配0-9或a-z或A-Z或_中的任意某1个字符
str7 = '_bc123'
result = re.match('\w', str7)
if result:print(result.group())
(6)匹配多个字符

image-20240828165042679

'''
正则三步走之查多少,到底要匹配多少个字符
普通字符或元字符* : 0或多,匹配前面的字符出现0次或多次,实际工作中,经常和.号配合使用,代表匹配任意字符.*
普通字符或元字符+ : 1或多,匹配前面的字符出现1次或多次,至少要出现1次,至多出现N次
普通字符或元字符? : 0或1,匹配前面的字符出现0次或1次
普通字符或元字符{m} : 匹配前面的字符出现m次
普通字符或元字符{m,} : 匹配前面的字符至少出现m次
普通字符或元字符{m,n} : 匹配前面的字符至少出现m次,至多出现n次注意:限定符,默认只能限定前面的第一个字符,比如10?,只能限定0不能限定1
101? 前面必须是10,1可以出现也可以不出现 => 首先匹配101,如果101匹配不到,则匹配10
'''
import re# 1、匹配连续的3位纯数字
str1 = '666abcd'
result = re.match('\d{3}', str1)
if result:print(result.group())# 2、匹配1或10开头的字符
str2 = '1abcabc'
result = re.match('10?', str2)
if result:print(result.group())# 3、匹配所有字符
str3 = '<img src="avatar.jpg">'
result = re.match('.*', str3)
if result:print(result.group())# 4、至少匹配连续4位字符(a-z)
str4 = 'abcdefg123'
result = re.match('[a-z]{4,}', str4)
if result:print(result.group())
(7)匹配字符串开头或者结尾

image-20240828165732092

'''
^ :托字节,^代表匹配以某个字符开头
$ :dollar美元符号,$代表匹配以某个字符结尾
注意:如果^托字节出现在[]字符簇中,则代表取反。如果单独出现,代表匹配以某个字符开头
案例:使用正则表达式匹配国内手机号码
手机号码 => 11位 => \d{11},不能这么写,因为手机号码要满足一定的规则
第1位必须是1
第2位必须是13、14、15、16、17、18、19,第2位必须是3或4或5或6或7或8或9
第3位开始~第11位,什么样的数字都有
手机验证:
1[3-9]\d{9}
'''
import re
mobile = input('请输入您的手机号码:')
result = re.match('^1[3-9]\d{9}$', mobile)
if result:print('合法的手机号码,发送短信验证码')
else:print('您输入的手机号码有误,请重新输入')
(8)提取分组数据

image-20240828172029427

  • 引入r:把正则中的转义字符当做普通字符使用

  • 选择匹配符

    • |可以匹配多个规则

    • # 选择匹配符
      result = re.finditer(r'hello(java|python)', 'hellojava, hellopython')
      if result:for i in result:print(i.group())
      else:print('未匹配到任何数据')
      
  • 子表达式:又叫分组,表达式中小括号括起来的部分就是子表达式

    • 正则表达式中\d(\d)(\d)中,(\d)(\d)就是子表达式,一共有两个()圆括号,则代表两个子表达式

    • re.search(r'\d(\d)(\d)', 'abcdef123ghijklmn')
      
  • 捕获:当正则表达式在字符串中匹配到相应的内容后,计算机系统会自动把子表达式所匹配的到内容放入到系统的对应缓存区中

    • image-20240828173238391

    • result = re.search(r'\d(\d)(\d)', 'abcdef123ghijklmn')
      print(result.group())   #123
      print(result.group(1))  #2
      print(result.group(2))  #3
      
  • 反向引用(后向引用)

    • 在正则表达式中,我们可以通过\num(num代表第num个缓存区的编号)来引用缓存区中的内容,我们把这个过程就称之为"反向引用"。

    • # 四个数字
      result =re.search(r'\d\d\d\d', 'abcdef1234ghijklmn7894')
      print(result.group()) # 1234# 四个数字叠字 1111  2222  3333  4444
      result =re.search(r'(\d)\1\1\1', 'abcdef1234ghijklmn33aaaa4444sese')
      print(result.group()) #4444
      
  • 分组别名

    • result = re.search(r'<(?P<mark>\w+)></(?P=mark)>', '<book></book>')
      print(result.group()) #'<book></book>'
      

这篇关于Python进阶07-高级语法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1123497

相关文章

python中各种常见文件的读写操作与类型转换详细指南

《python中各种常见文件的读写操作与类型转换详细指南》这篇文章主要为大家详细介绍了python中各种常见文件(txt,xls,csv,sql,二进制文件)的读写操作与类型转换,感兴趣的小伙伴可以跟... 目录1.文件txt读写标准用法1.1写入文件1.2读取文件2. 二进制文件读取3. 大文件读取3.1

使用Python实现一个优雅的异步定时器

《使用Python实现一个优雅的异步定时器》在Python中实现定时器功能是一个常见需求,尤其是在需要周期性执行任务的场景下,本文给大家介绍了基于asyncio和threading模块,可扩展的异步定... 目录需求背景代码1. 单例事件循环的实现2. 事件循环的运行与关闭3. 定时器核心逻辑4. 启动与停

基于Python实现读取嵌套压缩包下文件的方法

《基于Python实现读取嵌套压缩包下文件的方法》工作中遇到的问题,需要用Python实现嵌套压缩包下文件读取,本文给大家介绍了详细的解决方法,并有相关的代码示例供大家参考,需要的朋友可以参考下... 目录思路完整代码代码优化思路打开外层zip压缩包并遍历文件:使用with zipfile.ZipFil

Python处理函数调用超时的四种方法

《Python处理函数调用超时的四种方法》在实际开发过程中,我们可能会遇到一些场景,需要对函数的执行时间进行限制,例如,当一个函数执行时间过长时,可能会导致程序卡顿、资源占用过高,因此,在某些情况下,... 目录前言func-timeout1. 安装 func-timeout2. 基本用法自定义进程subp

Python实现word文档内容智能提取以及合成

《Python实现word文档内容智能提取以及合成》这篇文章主要为大家详细介绍了如何使用Python实现从10个左右的docx文档中抽取内容,再调整语言风格后生成新的文档,感兴趣的小伙伴可以了解一下... 目录核心思路技术路径实现步骤阶段一:准备工作阶段二:内容提取 (python 脚本)阶段三:语言风格调

Python结合PyWebView库打造跨平台桌面应用

《Python结合PyWebView库打造跨平台桌面应用》随着Web技术的发展,将HTML/CSS/JavaScript与Python结合构建桌面应用成为可能,本文将系统讲解如何使用PyWebView... 目录一、技术原理与优势分析1.1 架构原理1.2 核心优势二、开发环境搭建2.1 安装依赖2.2 验

Java使用ANTLR4对Lua脚本语法校验详解

《Java使用ANTLR4对Lua脚本语法校验详解》ANTLR是一个强大的解析器生成器,用于读取、处理、执行或翻译结构化文本或二进制文件,下面就跟随小编一起看看Java如何使用ANTLR4对Lua脚本... 目录什么是ANTLR?第一个例子ANTLR4 的工作流程Lua脚本语法校验准备一个Lua Gramm

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字

一文详解如何在Python中从字符串中提取部分内容

《一文详解如何在Python中从字符串中提取部分内容》:本文主要介绍如何在Python中从字符串中提取部分内容的相关资料,包括使用正则表达式、Pyparsing库、AST(抽象语法树)、字符串操作... 目录前言解决方案方法一:使用正则表达式方法二:使用 Pyparsing方法三:使用 AST方法四:使用字

Python列表去重的4种核心方法与实战指南详解

《Python列表去重的4种核心方法与实战指南详解》在Python开发中,处理列表数据时经常需要去除重复元素,本文将详细介绍4种最实用的列表去重方法,有需要的小伙伴可以根据自己的需要进行选择... 目录方法1:集合(set)去重法(最快速)方法2:顺序遍历法(保持顺序)方法3:副本删除法(原地修改)方法4: