在开始正题之前讲一下打开文件的另一种方式。

之前打开文件的方式f = open("文件路径","文件打开方式", encoding="utf8")

模式 描述
r 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
rb 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。
r+ 打开一个文件用于读写。文件指针将会放在文件的开头。
rb+ 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。
w 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
w+ 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb+ 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
a 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
ab 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
a+ 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
a+ 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。

新的打开方式:with open("文件路径","文件打开方式", encoding="utf8") as f:

旧方式文件打开

Python提供了 with 语句的这种写法,既简单又安全,并且 with 语句执行完成以后自动调用关闭文件操作,即使出现异常也会自动调用关闭文件操作

1
2
3
4
5
6
# 1、以读的方式打开文件
f = open("1.txt", "r")
# 2、读取文件内容
f.write("hello world") # 会报错,没有写权限
# 3、关闭文件
f.close()

安全写法:

1
2
3
4
5
6
7
8
9
10
11
12
try:
# 1、以读的方式打开文件
f = open("1.txt", "r")
# 2、读取文件内容
f.write("xxxxx")

except IOError as e:
print("文件操作出错", e)

finally:
# 3、关闭文件
f.close()

with写法

1
2
3
4
# 1、以写的方式打开文件
with open("1.txt", "w") as f:
# 2、读取文件内容
f.write("hello world")

深拷贝和浅拷贝

(不可变类型有: 数字、字符串、元组)(可变类型有: 列表、字典、集合)

  • 浅拷贝使用copy.copy函数
  • 深拷贝使用copy.deepcopy函数

summary:

  • 浅拷贝

    • 不可变类型进行浅拷贝不会给拷贝的对象开辟新的内存空间,而只是拷贝了这个对象的引用
    • 对可变类型进行浅拷贝,会开辟新的内存空间.
    • 对可变类型的子集进行浅拷贝,只是拷贝了子集的引用
  • 深拷贝

    • 不可变类型和浅拷贝基本没有区别,都是拷贝对象的引用(但是元组里面如果有可变类型,深拷贝会开辟内存存储
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import copy

# 对int数字类型进行浅拷贝,
a1 = 100
b1 = copy.copy(a1)
# 分别查看a1,b1变量的内存地址
print(id(a1))
print(id(b1))
# 结论:不可变类型进行浅拷贝不会给拷贝的对象开辟新的内存空间,而只是拷贝了这个对象的引用。

# 对可变类型进行浅拷贝
array1 = [1, 2, 3]
array2 = copy.copy(array1) # 使用copy.copy()函数进行拷贝
print(id(array1))
print(id(array2))
# 对可变类型进行浅拷贝,会开辟新的内存空间.

# 对可变类型的子集进行浅拷贝比如列表里面嵌套列表
a2 = [1, 2, [2, 3]]
b2 = copy.copy(a2)

print(id(a2))
print(id(b2))
print(id(a2[2])) # 内存值为970947576200
print(id(b2[2])) # 内存值为970947576200
# 对可变类型的子集进行浅拷贝,只是拷贝了子集的引用

# ---------------------------- 深拷贝 ----------------------------
# 使用copy.deepcopy()
# 只要发现对象有可变类型就会对该对象到最后一个可变类型的每一层对象就行拷贝, 对每一层拷贝的对象都会开辟新的内存空间进行存储
a3 = 200
b3 = copy.deepcopy(a3)
print(id(a3))
print(id(b3)) # 不可变类型和浅拷贝基本没有区别,都是拷贝对象的引用(但是元组里面如果有可变类型,深拷贝会开辟内存存储

a4 = ['张三']
b4 = copy.deepcopy(a4)
print(id(a4))
print(id(b4)) # 对可变类型进行深拷贝和浅拷贝差不多,都是会开辟内存空间

正则表达式(Regular Expression)

match 和 group用法

1
2
3
4
5
6
7
import re

# 使用match方法进行匹配操作,match里面填写的是要匹配的字符串
result = re.match("000", "0009929032000")
# 如果匹配到数据的话,可以使用group方法来提取数据,如果没有匹配到数据会报错AttributeError: 'NoneType' object has no attribute 'group'
info = result.group(0)
print(info)

匹配单个字符

. 任意单个字符, [] 括号列举的字符, /d 数字 /D 非数字, /s 空白 /S 非空白, /w 非特殊字符(数字字母汉字下划线 /W 特殊字符

匹配多个字符(数量词)

这些都是数量词,用于形容前面的字符,当两个量词同时出现的时候就不单单代表量词了.

*匹配前一个字符0到多次, + 匹配前一个字符1到多次, ? 匹配前一个字符0-1次(非贪婪匹配), {m} 匹配前一个字符m次,{m,n} 匹配前一个字符m到n次

浅析贪婪匹配和非贪婪匹配

不是很了解只能说,只知道?这个特殊字符是非贪婪匹配模式。

比如字符串: booooboby123, 我需要的子串是boooob但是如果正则式

  • b.*b: 会匹配到boooobob不是我想要的
  • b.*?b: 会匹配到boooob, 是我需要的.*?两个量词同时出现? 就不代表匹配0到1次了,而是非贪婪匹配的意思.

Example

1
2
3
4
5
6
7
8
9
10
import re

line = "booooboby123"
regex_srt = ".*?(b.*?b).*" # 这里原来是想要匹配boooob,但是由于贪婪匹配+从后到前导致匹配到bob
# 改为.*?(b.*b).* 发现可以匹配但结果为boooobob,后面的ob不是我想要的
# 改为.*?(b.*?b).* 最终可以匹配到boooob

match_obj = re.match(regex_srt, line)
if match_obj:
print(match_obj.group(1))