python是面向对象语言,在python中,万物皆对象。
变量:变量是用来临时保存数据的,程序是用来处理数据的。
变量的类型
- 数字number: 不可变类型。int 有符号整型、long 长整型、float 浮点型、complex 复数
- 字符串string:不可变类型。
可以自己定义也可以使用类来定义,如name=str();可以使用三引号来赋值,这种方法可以保留字符串的文本格式.
取值时,需传入一个正常的下标(从0开始)索引,如mystr[0]。从右到左的话是从-1开始(-1,-2,-3…)如mystr[-1]
切片(截取):
语法:[起始下标:结束下标:步长] 步长可省略,默认为1。 左闭右开,不包含结束下标。
若从头部开始,0可以省略,即[:结束下标]。
[::-1] 将字符串反转,从右往左读,步长为1
-
列表list:可变类型 []。基本操作与字符串相同
创建列表五种方式:
List.append()
List.insert()
List+[] 列表相加
List=[x for x in range(10)]
list=list(range(10)) -
元组tuple:不可变类型 () 。
如果元组中只有一个元素时,后面必须加逗号,否则将视为加了括号的int型,如tuple=(1,)。
元组不可以修改或删除元素,只能查看或遍历元素。
- 字典dictionary:可变类型 {key1:value1,key2:value2,…}
key值的数据类型必须是不可变类型,即数字,字符串,元组。字典是无序的。
字典的常用操作:
修改元素:mydict[key] =value 通过key修改对应的value。
添加元素:mydict[key] =value 若key存在,则覆盖原来的值,若不存在则创建新的元素。
删除元素:del mydict[key]
mydict.clear() 清空字典,相当于初始化
list(mydict.keys()) 返回字典中所有的key的列表
list(mydict.values()) 返回字典中所有的value的列表
mydict.items() 返回一个包含所有(键,值)元祖的列表。返回[(key1,value1),(key2,value2)…]
for key,value in mydict.items() key和value都是临时别量,分别代表字典中的key值和value值。
- 布尔类型bool:True、False 不可变类型
标识符:由字母、数字和下划线组成,且不能以数字开头
关键字:一些具有特殊功能的标识符。
查看所有的关键字:
import keyword
print(keyword.kwlist)
输入:
input() 在python3中输入之后得到的结果是字符串类型,与python2中raw_input()的结果一样,但是python2中的input()得到的结果取决于用户自己输入的类型
如:name = input(“请输入您的名字”)
输出:
print()默认自动换行,即print(‘’,end=’\n’)。可以指定结尾输出,如print(‘’,end=’’)指定不换行
格式化输出:
一个变量格式化输出:
age =18
print(“小明的年龄%d岁” % age)
多个变量格式化输出:
print(“名字%s 年龄%d岁” % (name,age))
常用格式化输出符号:
%d int型(%2d 显示两位输出,如果只有1位,使用空格占位,默认右对齐,若想左对齐,则用%-2d);
%s 字符串;
%f float型,默认保留小数点后6位(%.2f 保留两位小数);
对于bool型,若想输出True或False,则用%s;若想输出0或1,则用%d
算数运算符:
加+ 减- 乘* 除/ 取整除//(9.0//2.0=4.0) 取余% 指数 **
逻辑运算符:
and: x and y 若x是False,则返回False,否则返回y的值
or: x or y 若x是True,则返回True,否则返回y的值
not:not x
条件语句 If…else…与elif :
Python 中没有if…if else嵌套: 需要用if…elif…
循环语句while与for:
for 临时变量 in 列表或字符串等可迭代对象:
循环执行语句
for ...else.. 和while ...else...:for循环或者while循环结束后,会执行else中的语句,但是若for循环或while循环中执行了break,else的语句将不会执行。
break 和continue:
配合循环使用。
执行break,则停止循环,直接跳出当前循环,且break后面的语句都不执行。
执行continue,则提前结束本次循环,直接进入当前循环中的下一次循环,continue后的代码不执行。
数据类型转换:
如:int(x) 将x转为int型,int(3.5)=3 直接去掉小数部分 、 float() 、str()、eval() 常与input()一起用
公共方法:
注:in在对字典操作时,判断的是字典的key
内置函数:
-
查看变量名或数值的数据类型:type(变量名或数值)
-
范围标识:range
range(1,5) 左闭右开(范围是1,2,3,4) range(x) 范围是0-x 可以用来单纯表示x次循环
-
计算字符串中字符个数(计算长度):len(str)
-
将序列中的元素以指定字符x连接生成一个新的字符串:’x’.join(sequence)
字符串常见操作函数:
注:此处的x可以是单个字符,也可以是字符串
- mystr.find(‘x’) 获取指定字符x在mystr字符串中的下标索引,若没有找到,返回-1。一旦找到就不继续找了。
- mystr.rfind(‘x’) 类似find()函数,不过是从右边开始找,但是返回下标值还是从左开始计算的
- mystr.index(‘x’) 与find一样的作用,但若没有找到时,会直接异常报错,所以一般使用find。
- mystr.rindex(‘x’) 类似index()函数,不过是从右边开始找,但是返回下标值还是从左开始计算的
- mystr.partition(‘x’) 将字符串以指定x分割成三部分,x前,x和x后,返回一个元组,里面的值为字符串类型。
- mystr.count(‘x’) 统计指定字符x在字符串mystr中出现的次数
- mystr.replace(‘x’,’y’,num) 将字符串中指定字符x修改为y,若指定次数num,则修改几个,若没有次数,则所有符合的都修改。
- mystr.split(‘x’) 将字符串以指定字符进行分割,返回结果为列表,列表中所有值为字符串类型
- mystr.splitlines() 按照行(换行符)分割
- mystr.capitalize() 使字符串第一个字符大写,产生一个新的字符串
- mystr.title() 使字符串的每个单词的首字母大写
- mystr.startswith(‘x’) 判断字符串是否以指定字符开头
- mystr.endswith(‘x’) 判断字符串是否以指定字符结尾
- mystr.lower() 将字符串所有大写字母小写
- mystr.upper() 将字符串所有小写字母大写
- mystr.ljust(n,’x’) 返回一个原字符串左对齐,并使用指定字符x填充字符串右边至长度n的新字符串
- mystr.rjust(n,’x’) 返回一个原字符串右对齐,并使用指定字符填充字符串左边至长度n的新字符串
- mystr.center(n,’x’) 返回一个原字符串居中对齐,并使用指定字符填充字符串左右两边至长度n的新字符串
- mystr.lstrip(‘x’) 删除字符串左边的指定字符,默认s.strip()是空白字符(空格 、换行、\t (tab键)都算空白字符)
- mystr.rstrip(‘x’) 删除字符串右边的指定字符,默认是空白字符
- mystr.strip(‘x’) 删除字符串两边的指定字符(字符可以组合,比如左边删除1,右边删除2,则可以写为’12’),默认是空白字符
- mystr.isalpha() 判断字符串中所有字符是否都是字母,若是返回True,否则返回False
- mystr.isdigit() 判断字符串中所有字符是否都是数字,若是返回True,否则返回False
- mystr.isalnum() 判断字符串中所有字符是否都是字母或数字,若是返回True,否则返回False
- mystr.isspace() 判断字符串是否只包含空格,若是返回True,否则返回False
列表常见操作函数:
添加元素:
- mylist.append(x) x作为一个整体对象插入到列表最后
- mylist.extend(x) x只能是一个可以遍历的对象(有序的字符序列),将x拆开一个个插入.如插入’1234’,其实是将1234分为1 2 3 4依次插入。
- mylist.insert(下标索引,x) 在指定下标索引位置之前插入指定整体对象x
查找元素:
- x in mylist 查找指定元素x是否在列表中
- x not in mylist 查找指定元素x是否不在列表中
- mylist.index(x) 查找指定元素x在列表中的下标索引
- mylist.count(x) 查找指定元素x在列表中出现的次数
删除元素:
- del mylist[下标索引]
- mylist.pop(下标索引) 若没有指定下标索引,默认从列表的后面开始删除 返回删除的值
- mylist.remove(x) 删除列表中的指定元素
- mylist.clear() 清空列表 相当于mylist =[]
元素排序:
- mylist.sort() 默认升序(从小到大)
- mylist.sort(reverse=True) 降序 (从大到小)
for i,value in enumerate(mylist) i和value都是临时别量,分别代表列表的下标和其对应的值。
元组中常用函数:
mytuple.index(x) 查找元组中元素x的索引下标
mytuple.count(x) 获取元素x在元组中出现的次数
字典中常用函数:
-
list(mydict.keys()) 返回字典中所有的key的列表
-
list(mydict.values()) 返回字典中所有的value的列表
-
mydict.items() 返回一个包含所有(键,值)元祖的列表。返回[(key1,value1),(key2,value2)…]
for key,value in mydict.items() key和value都是临时别量,分别代表字典中的key值和value值。
位置参数与关键字参数:
位置参数必须一一对应:def test(a,b) test(1,2) 则a=1 b=2
关键字参数没有顺序要求:def test(a,b) test(b=1,a=2) 则a=2 b=1
注:当位置参数与关键字参数混合使用时,位置参数必须放在前面,关键字参数放在后面;如果某个参数使用了关键字参数,则其后面的所有参数都需要使用关键字参数。
缺省参数:给形参定义一个默认值,若调用函数时提供了实参,那就使用实参,若没有提供就使用默认值(缺省参数);在定义函数时,若某个形参使用了缺省参数,那其后面的形参都需要使用缺省参数。
拆包: 如:a,b,c=[1,2,3] 即a=1 b=2 c=3
拆包时要注意,需要拆的数据的个数要与变量的个数相同,否则程序会异常
除了对元组拆包之外,还可以对列表、字典等拆包,其中对字典拆包时,取出的值是key。
交换变量的值:
a,b =4,5 赋值 a=4 b=5
a,b=b,a 同时给a,b重新赋值a=b b=a,即交换a,b 的值 即a=5 b=4
全局变量: global a
*args 、**kwargs
args 可变的参数列表,接收的参数用元组存储
**kwargs 键值对参数列表,接收的参数类型是键值对,用字典存储。
**kwargs对应的参数必须放在args对应的参数后面
列表list和元组的区别、列表和set的区别
-
列表和元组的区别:
列表可变,元组不可变。 元组无法复制。 原因是元组是不可变的。 如果运行tuple(tuple_name)将返回自己。
-
列表和set集合的区别:
列表是有序的,元素可以重复;
集合无序,会自动过滤重复的数据
匿名函数:
lambda表达式
- 无参数无返回值的函数:
f=lambda:print(‘aaa’) f() 其中lambda相当于函数的定义def,:后面的是函数执行语句,函数名为等号左边的值,调用时用f()。等价于(lambda:print(‘aaa’) )() - 无参数有返回值的函数:
f = lambda:3.14 f() 返回3.14 - 有参数无返回值的函数:
f = lambda name:print(name) f(‘张三’) - 有参数有返回值的函数:
f = lambda a,b:a+b f(1,2) 返回3
如对字典进行排序,依据key值排序:
方法一,用sort():
d = {1:3,5:2,4:4}
d = list(d.items()) #转为list类型,才可以用sort
d.sort(key=lambda x:x[0]) #如果要用value排序,则为x[1],若要降序排列, 则使用sort(key=xxx ,reverse=True)
print(d)
方法二,用sorted()
d = {1:3,5:2,4:4}
sorted(d.items(),key=lambda x:x[0])
print(d)
注:不管是sort还是sorted中的key都是一个匿名函数,参数为前面的列表,遍历列表取值,返回给sorted作为排序依据。d.items()将原来的字典中的键值对,分别搜存入到一个元组中–>(key,value),生成一个元组列表,即[(key1,value1),(key2,value2),(key3,value3)]
文件操作:
open(文件名,访问模式)
访问模式:r只读 w只写(会把原来数据清空,再写) a追加写
打开文件:f = open(‘a.txt’,’r’) 返回一个文件对象
关闭文件:f.close()
-
写数据:以只写模式打开文件
f = open(‘a.txt’,’w’) f.write(‘aaaaa’) 文件不存在时就创建该文件 写入中文: window的电脑中保存中文编码格式为gbk,字符是utf-8,所以写中文时需要指定格式为utf-8,即f = open(‘a.txt’,’w’,encoding=’utf-8’)
-
读数据: 以只读模式打开文件
f = open(‘a.txt’,’r’) f.read(n) 若指定n则从文件开始读n个字符 f = open(‘a.txt’,’r’) f.readlines() 一次性读文件中的每行数据,并保存到列表中,每一行的数据为一个元素 f = open(‘a.txt’,’r’) f.readline() 读一行
文件备份:
1、打开原文件f=open(‘a.txt’,‘r’)
2、读取数据result=f.read()
3、创建备份文件f2=open(‘a2.txt’,’w’)
4、将读取的内容写入进备份文件f2.write(result)
5、关闭两个文件
注:通过此方法打开文件不需要关闭:with open(…) as f:
excel文件的读取和写入:
- 写入:
# 导入模块import xlsxwriter
# 打开student.xlsx文件 若没有则自动创建
workbook = xlsxwriter.Workbook("student.xlsx")
# 创建一张工作表
worksheet = workbook.add_worksheet()
# 设置第一行信息
worksheet.write(0, 0, "学号") 第一列
worksheet.write(0, 1, "姓名") 第二列
worksheet.write(0, 2, "年龄") 第三列
# 学生信息列表
student_list = [{"name": "小明", "age": 20, "no": "20170901001"},
{"name": "小红", "age": 21, "no": "20170901002"},
{"name": "小刚", "age": 20, "no": "20170901003"},
{"name": "小海", "age": 23, "no": "20170901004"},
{"name": "小阳", "age": 25, "no": "20170901005"}]
# 遍历列表for i, info in enumerate(student_list):
# 写入数据
# write(第x行, 第x列, 写入的数据)
worksheet.write(i + 1, 0, info["no"])
worksheet.write(i + 1, 1, info["name"])
worksheet.write(i + 1, 2, info["age"])
# 关闭文件
workbook.close()
- 读取:
# 导入模块import xlrd
# 读取到excel文件
data = xlrd.open_workbook("student.xlsx")
# 获取列表 第一张表
table = data.sheet_by_index(0)
# 获取所有的行数
nrows = table.nrows
# 获取所有的列数
ncols = table.ncols
# 获取第一行的数据
first_row_name_list = table.row_values(0)
print(first_row_name_list)
# 定义一个列表保存所有行的数据
info_list = []
# 遍历所有行
for rownum in range(1, nrows):
# 获取
row = table.row_values(rownum)
# 如果row有数据
if row:
info_list.append(row)
print(info_list)
json文件的写入与读取:
- 读取:
# 导入模块import json
# 将json对象转成字典 -> 进行解码
with open("hm.json", "r", encoding="utf-8") as f:
# 获取文件中数据 -> 字典
new_dict = json.load(f)
print(new_dict["name"]) # 获取名字
print(new_dict["age"]) # 获取年龄
print(new_dict["no"]) # 获取学号
- 写入:
# 导入模块import json
# 定义一个字典
my_dict = {"name": "老王", "age": 30, "no": "007"}
# 将字典转成json -> 进行编码
json_str = json.dumps(my_dict)
# 把json数据写入到文件中
with open("hm.json", "w", encoding="utf-8") as f:
f.write(json_str)
xml文件读取:
将xml文件转为json文件读取更方便,使用XmlToJson
模块:
- import 模块名 导入模块中的所有东西,使用时需要加上模块名。
- from 模块名 import 模块中的全局变量,函数名,类名 这种方式导入,在使用时不需要写模块名。
- from 模块名 import * 导入模块中所有内容 使用时不需要写模块名。
- from 模块名 as 别名 将导入的模块重命名 也可以在导入全局变量或者函数或者类时重命名
注:如果一个模块中使用了__all__ ,则只有在__all__的列表中的字符串才可以在其它模块中使用,而其它模块必须是通过from 模块名 import * 方式导入该模块的。
随机模块(函数):random 生成随机数。如random.randint(0,2) 此处是闭区间,随机生成大于等于0小于等于2的整数。
os模块:
重命名: os.rename(需要修改的文件名,新的文件名)
删除文件:os.remove(待删除的文件)
创建文件夹:os.mkdir(文件夹名)
删除文件夹:os.rmdir(文件夹名) 文件夹必须是空的
获取当前目录:result=os.getcwd() 获取当前路径
改变默认目录:os.chdir(路径) 将当前目录修改为指定目录路径(进入指定目录)
获取目录列表:r = os.listdir()
获取文件夹下的所有文件:for root,dirs,file in os.walk("目录"):
root 表示正在遍历的文件夹的名字(根/子)
dirs 记录正在遍历的文件夹下的子文件夹集合
files 记录正在遍历的文件夹中的文件集合
re模块:
re.search(str1,str2) 扫描整个字符串查找匹配str2在str1中的开始位置
re.match(str1,str2)只在字符串str1的开始位置匹配,若开始位置不匹配返回None。
re.search().group()、re.match().group() 返回匹配到的字符串。
面向对象和面向过程
- 面向过程:根据业务逻辑从上到下写代码(类似于什么事情都自己亲历亲为去做)
- 面向对象:将数据与函数绑定到一起,进行封装,这能够更快速的开发程序,减少了重复代码的重写过程(类似于委托给一个专业的人去做,自己一样得到结果)
类是创建对象的模板,是多个对象的集合,对象是类的实例化。
类:
- 定义类:
class 类名:
方法列表:
如:class Hero:
class Hero():
class Hero(object): 建议写这种
注:object是所有类的父类;
以上三种都是python2中产生,前两种没有父类,第三种的父类是object。在python3中,以上三种写法的父类都是object类。
- 创建对象:
class Hero(object):
def move(self): 哪个对象调用了方法,那么self就是哪个对象
pass
def info(self):
print(self.name)
Wukong = Hero() 通过类来创建对象
Wukong.move() 使用对象调用类中的方法
Wukong.name =’悟空’ 为对象添加属性
print(Wukong.name) 获取对象身上的属性
print(Wukong.info()) 通过调用对象方法来获取属性
魔法方法:
在python重中 ,以__开头,并以__结尾的方法。
-
__init __ (self)方法:初始化方法,对象创建时自动调用。
-
有参数的__init__()方法:
def __init__(self,new_name,参数2,...) self不能去掉。 self.name = new_name
在类内部获取 属性 和 实例方法,通过self获取;
在类外部获取 属性 和 实例方法,通过对象名获取。
- __str __(self)方法:实现父类下已有的魔法方法,不可以添加参数(形参),会返回一个字符串,打印对象就会调用,主要用于开发调试时追踪属性变化。
- __del __(self)方法:监听对象销毁,引用计数自动管理内存,只有当引用计数为0时,才会调用del魔法方法。
- __new __(cls,*args,**kwargs): return object.__new __(cls) 监听python 使用其类创建对象,并返回对象给__init__方法。
继承:
- 单继承:子类只继承了一个父类。 class B(A) B类继承A类,B继承了A中所有的方法和属性。
- 多继承:子类继承多个父类。class B(A,C) 如果A,C类中的方法名不同,调用后子类都会执行,若方法名相同,子类会执行第一个父类的,即A类
子类重写父类的同名属性和方法:若重写了就会默认使用子类的方法和属性
子类调用父类同名属性和方法:语法:父类名.对象方法名(self)
通过 supper(子类类名,self).父类方法() 或者简写(supper().父类方法)调用父类的方法,默认调用第一个父类的方法,适用于单继承或者只想使用第一个父类的方法。 适用于第三种创建类的写法。
私有属性和私有方法:
-
私有属性:如果一个属性的名字开头是两个下划线,就代表这个属性私有。如self.__money=1000。
如果属性私有,那么就不能使用对象调用这个属性,只能在类的里面使用。
-
私有方法:形如私有属性,对象不能调用私有方法,只能在类里面使用。
注:子类不能继承父类的私有方法和私有属性 -
获取、修改私有属性的值:
-
在类中定义一个方法,在方法中获取私有属性的值并返回(一般方法名中使用get),然后再用对象调用该方法。
-
在类中定义一个方法,在方法中给私有属性赋值(一般方法名中使用set),然后再用对象调用该方法,并传入一个实参赋值,最后再调用获取属性值的方法。
多态:
多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作。
同一个事件发生在不同对象上,产生不一样的结果。
类属性和实例属性:
- 使用实例属性(类的方法中定义的属性):对象名.实例属性名
- 修改实例属性:对象名.实例属性名=值
- 使用类属性(定义在类中,类方法外的属性):类名.类属性名;对象名.类属性名
- 修改类属性:类名.类属性名=值
注:多个对象调用类属性,类属性只占一个内存,但是多个对象调用同一个实例属性占多个内存
类方法:是类对象所拥有的方法,需要用修饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数,能够通过实例对象和类对象去访问。
静态方法: 需要通过修饰器@staticmethod来进行修饰,静态方法不需要多定义参数,可以通过对象和类来访问。
class Person(object): # 自定义类
__country = "中国" # 私有的类属性(国籍)
# 构造方法
def __init__(self):
self.name = "小明"
# 私有属性
self.__age = 20
# 实例方法(对象方法)获取私有属性
def get_age(self):
return self.__age
# 实例方法(对象方法)修改私有属性
def set_age(self, new_age):
self.__age = new_age
# 类方法 获取私有类属性
@classmethod
def get_country(cls):
return cls.__country
# 类方法 修改私有类属性
@classmethod
def set_country(cls, new_country):
cls.__country = new_country
# 静态方法
@staticmethod
def hello():
print("今天天气不错")
# 使用静态方法# 01: 类名.静态方法名
Person.hello()
# 02: 对象名.静态方法名
xiaoming = Person()
xiaoming.hello()
# 实例方法
xiaoming.get_country()
Person.get_age(Person())
python中类中的方法总结:
-
实例方法(对象方法) -> 场景很多
- 定义格式: def 实例方法名(self):
- 调用格式: 对象名.实例方法名()
- 使用场景: 在方法中需要self
-
类方法-> 对私有类属性取值或者赋值
- 定义格式:
@classmethod
def 类方法名(cls): - 调用格式: 类名.类方法名() 或者 对象名.类方法名()
- 使用场景: 在方法中需要cls(类名)
- 定义格式:
-
静态方法 -> 一般不用
- 定义格式:
@staticmethod
def 静态方法名(): - 调用格式: 类名.类方法名() 或者 对象名.类方法名()
- 使用场景: 在方法中不需要self 也不需要cls
- 定义格式:
单例模式:
在程序中这个类创建出来的对象只有一个,也就是占用一份内存。单例模式时,只执行一次__init __
实例化一个单例
class Singleton(object):
__instance = None
def __new__(cls, age, name):
#如果类属性__instance的值为None,
#那么就创建一个对象,并且赋值为这个对象的引用,保证下次调用这个方法时
#能够知道之前已经创建过对象了,这样就保证了只有1个对象
if not cls.__instance:
cls.__instance = object.__new__(cls)
return cls.__instance
a = Singleton(18, "dongGe")
b = Singleton(8, "dongGe")
print(id(a))
print(id(b)) 返回结果是一样的
异常:
- 捕获异常:可以使程序遇到错误时,继续执行后面的代码,保证程序正常运行
语法:
try:
执行可能发生异常的代码
except 异常类型:
如果发生异常执行的代码
- 捕获多个异常:
语法:
try:
执行可能发生异常的代码1(1和2是不同的异常类型)
执行可能发生异常的代码2
except (异常类型1,异常类型2):
如果发生异常执行的代码
- 捕获异常信息描述:
语法:
try:
执行可能发生异常的代码
except 异常类型 as e: (注:as 临时变量 使用临时变量保存异常的信息描述)
print(e)
- 捕获所有异常:
语法:
try:
执行可能发生异常的代码
except Exception: 可以直接去掉Exception,仅使用except
如果发生异常执行的代码
注:捕获所有异常的描述信息跟捕获异常信息一样的使用临时变量即可。
try:
执行可能发生异常的代码
except:
如果发生异常执行的代码
else:
如果没有发生异常执行的代码
finally:
无论try中异常是否发生都会执行的代码
如果finally中有return,会覆盖try和excep中的return。
python的垃圾回收
1、引用计数,python内置有一个计数器,程序中的变量若进行引用,计数就加1,若为0,就由魔法函数__del__自动回收。
2、垃圾回收,使用del进行回收。
3、内存池,用于对小块内存的申请和释放管理。创建大量消耗小内存的对象时,频繁调用new/malloc会导致大量的内存碎片,致使效率降低。内存池就是预先在内存中申请一定数量的,大小相等的内存块留作备用,当有新的内存需求时,就先从内存池中分配内存给这个需求,不够了之后再申请新的内存,能够减少内存碎片,提升效率。
GIL锁:全局解释器锁
http://t.zoukankan.com/youhongliang-p-12194163.html
互斥锁:多线程时,保证修改共享数据时不会产生数据混乱
内存管理机制
https://blog.51cto.com/u_15127604/3852086
常用模块
Python常用的模块 - 知乎 (zhihu.com)
Python(十三)- 常用内置模块与第三方库_Alfred_|_derflA的博客-CSDN博客_python的内置库和第三方库