一、内存管理
1.内存管理基础
内存分为栈区间和堆区间,栈区间的内存是系统自动申请自动释放;堆上的内存需要程序通过调用malloc函数去申请,通过free函数去释放
高级语言(java\C++\OC\Python)中的内存管理机制,都是针对堆上的内存管理进行自动化操作
2.Python的内存管理机制
1)内存的申请
python中所有的数据都是存在堆中的,变量是保存在栈区间的,变量中保存的是保存在堆中的数据的地址。
重新给变量赋值,会先在内存空间开辟新的内存保存数据,然后新的数据的地址重新保存到变量,但是若果使用数字或字符串给变量赋值,不会直接开辟新的内存,而是先检查内存中有没有这个数据,如果有,直接将原来的数据的地址给变量
2)内存的释放(垃圾回收机制)
在python中一个数据对应的内存空间是否要释放,就看这个数据的引用计数是否为0,如果引用计数为0,数据对应的内存就会被释放
循环引用的问题:python的垃圾回收机制会自动处理循环引用的问题
增加引用计数:增加数据的引用(让更多的变量来保存数据的地址)
减少引用计数:删除引用,或者让引用去保存新的数据
print('======================内存申请====================')
a = 10
print(id(a))
a = 100
print(id(a))
b = []
print(id(b)) # 4495144200
b = []
print(id(b)) # 4495187272
c = {'a': 10}
print(id(c)) # 4493576304
c = {'a': 10}
print(id(c)) # 4493576376
d = 100
print(id(d)) # 4491424800
d = 100
print(id(d)) # 4491424800
e = 'abc'
print(id(e)) # 4484038984
e = 'abc'
print(id(e)) # 4484038984
print('=========================内存释放======================')
list1 = [1, 2, 3] # re: 1
print(getrefcount(list1)) # 2
list2 = list1
print(getrefcount(list1)) # 3
dict1 = {'a': list1}
print(getrefcount(list1), getrefcount(list2)) # 4
del list1
print(getrefcount(list2)) # 3
dict1['a'] = 'abc'
print(getrefcount(list2)) # 2
# 循环引用
list1 = [1, 2, 3]
list2 = [list1, 10, 20]
list1.append(list2)
del list1
del list2
class Person:
pass
Person()
list3 = [[100, 200], 20, 30, 40]
# del list3[0]
list3.pop(0)
num = 6
print(getrefcount(num))
二、拷贝
from copy import copy, deepcopy
class Dog:
def __init__(self, name, color='黄色'):
self.name = name
self.color = color
def __repr__(self):
return '<%s __id: %s>' % (str(self.__dict__)[1:-1], id(self))
class Person:
def __init__(self, name, age=10, gender='男', dog=None):
self.name = name
self.age = age
self.gender = gender
self.dog = dog
# 这个函数会在打印当前类的对象的时候自动调用; 函数的返回值就是打印的结果
# 返回值是字符串
def __repr__(self):
return '<%s __id: %s>' % (str(self.__dict__)[1:-1], id(self))
# 1.直接赋值
# 用一个变量直接给另外一个变量赋值的时候赋的地址;赋值后两个变量保存的是同一个数据的地址
print('直接赋值')
p1 = Person('小明', dog=Dog('大黄'))
p2 = p1 # 赋值后p1和p2指向是同一个Person对象
print('p1:', p1)
print('p2:', p2)
p1.gender = '女'
p1.dog.color = '白色'
print('p1:', p1)
print('p2:', p2)
# 2.浅拷贝
# 复制原数据产生一个新的数据(值和原数据一样,地址不同),然后将新的数据的地址返回; 如果有子对象,子对象不会复制
print('=============浅拷贝==============')
p1 = Person('小明', dog=Dog('大黄'))
p2 = copy(p1)
print(p1)
print(p2)
p1.gender = '女'
p1.dog.color = '白色'
print('p1:', p1)
print('p2:', p2)
# 3.深拷贝
# 复制原数据产生一个新的数据(值和原数据一样,地址不同),然后将新的数据的地址返回; 如果有子对象,子对象也会复制
print('=============深拷贝===========')
p1 = Person('小花', dog=Dog('大黄'))
p2 = deepcopy(p1)
print('p1:', p1)
print('p2:', p2)
p1.gender = '女'
p1.dog.color = '白色'
print('p1:', p1)
print('p2:', p2)
三、正则表达式
1.什么是正则表达式
用正则符号来描述字符串规则让字符串匹配更加简单的一种工具
正则本身的语法和语言无关,几乎所有的编程语言都支持正则表达式
python通过re模块来支持正则表达式
2.正则符号
匹配符号:一个匹配字符能且仅能匹配一个字符
1)普通字符 - 在正则表达式中没有特殊功能或者特殊意义的字符都是普通字符
普通字符在正则表达式中就代表了这个符号本身,匹配的时候只能喝这个指定的字符进行匹配
2). - 代表任意字符
一个.代表一个任意字符
3)\w - ASCII表中只能匹配字母、数字或者下划线,ASCII表以外的都可以匹配
4)\d - 匹配任意一个数字字符
5)\s - 匹配任意空白字符(任意能产生空白效果的字符)
6)\W, \D, \S
\W - 匹配任意非字母、数字、下划线、ASCII表以外的字符
\D - 匹配任意非数字字符
\S - 匹配任意非空白字符
7)[字符集] - 匹配字符集中的任意一个字符
注意:一个中括号只能匹配一个字符
a. [普通字符集] 例如: [abc] - 匹配a,b,c三个字符中的任意一个
b. [字符1-字符2] 例如: [1-9] - 匹配123456789中的任意一个字符
注意:字符1的编码值必须小于字符2的编码值
8)[^字符集] - 匹配除了字符集以外假的任意一个字符
检查符号:只匹配不检查
1)\b - 检查是否是单词结尾
单次结尾 - 所有可以区分出两个不同单词的符号都是单词结尾,其中字符串开头和字符串结尾
用法:检测\b所在的位置是否是单词结尾;不影响匹配的时候的字符串的长度
2)^ - 检测字符串开头
判断^所在位置是否是字符串开头
3)所在位置是否是字符串结尾
匹配次数
1)? - 匹配0次或一次
x? - x出现0次或1次
2)*
- 匹配0次或多次
x*
- x出现0次或多次
3)+ - 匹配1次或多次
x+ - x出现1次或多次
4){}
{N} - 匹配N次
{M,N} - 匹配M到N次
{,N} - 匹配至多N次
{M,} - 匹配至少M次
# 2.正则符号
print('=========================匹配符号===========================')
# 1) 普通字符 - 在正则表达式中没有特殊功能或者特殊意义的字符都是普通字符
# 普通字符在正则表达式中就代表这个符号本身,匹配的时候只能和这个指定的字符进行匹配
# re_str = r'1[3-9]\d{9}' # python
# re_str = /1[3-9]\d{9}/
re_str = r'abc'
result = re.fullmatch(re_str, 'abc')
print(result)
# 2) . - 代表任意字符
# 注意: 一个.代表一个任意字符
re_str = r'a.b' # 匹配一个长度是3的字符串,第一个字符是a,最后一个字符是b, 中间是任意字符
print(re.fullmatch(re_str, 'abc')) # None
print(re.fullmatch(re_str, 'a你b'))
print(re.fullmatch(r'a..b', 'au9b'))
# 3) \w - ASCII码表中只能匹配字母、数字或者下划线;ASCII码表以外的都可以匹配
# 注意: 一个\w只能匹配一个字符
re_str = r'a\wb'
print(re.fullmatch(re_str, 'awb'))
print(re.fullmatch(re_str, 'a8b'))
print(re.fullmatch(re_str, 'a_b'))
print(re.fullmatch(re_str, 'a+b')) # None
print(re.fullmatch(re_str, 'a胡b'))
# 4) \d - 匹配任意一个数字字符
re_str = r'a\d\db'
print(re.fullmatch(re_str, 'a23b'))
print(re.fullmatch(re_str, 'a33b'))
print(re.fullmatch(re_str, 'aa3b')) # None
# 5) \s - 匹配任意一个空白字符
re_str = r'a\sb'
print(re.fullmatch(re_str, 'a b'))
print(re.fullmatch(re_str, 'a\tb'))
print(re.fullmatch(re_str, 'a\nb'))
print(re.fullmatch(re_str, 'a b')) # None
# 6) \W, \D, \S
# \D - 匹配任意非数字字符
print(re.fullmatch(r'a\Db\Sc\Wd', 'aZb=c+d'))
print(re.fullmatch(r'a\Db\Sc\Wd', 'a2b=c+d')) # None
print(re.fullmatch(r'a\Db\Sc\Wd', 'aZb c+d')) # None
print(re.fullmatch(r'a\Db\Sc\Wd', 'aZb=c胡d')) # None
# 7) [字符集] - 匹配字符集中的任意一个字符
"""
注意: 一个[]只能匹配一个字符
a. [普通字符集] 例如: [abc] - 匹配a、b、c三个字符中的任意一个
[aA123] - 匹配a、A、1、2、3中的任意一个字符
b. [字符1-字符2] 例如: [1-9] - 匹配123456789中的任意一个字符
[0-9] - \d
[a-z] - 匹配任意一个小写字母
[A-Z] - 匹配任意一个大写字母
[a-zA-Z] - 匹配任意一个字母
[\u4e00-\u9fa5] - 匹配任意一个中文字符
[1-9abc] - 匹配1~9或者abc中的任意一个字符
[a-zA-Z0-9_] - 匹配字母数字下划线
[\dxyz] - 任意数字或者x、y、z
注意: 字符1的编码值必须小于字符2的编码值
"""
print(re.fullmatch(r'a[xyz89?]b', 'azb'))
print(re.fullmatch(r'a[xyz]b', 'anb'))
print(re.fullmatch(r'a[23456789]b', r'a7b'))
print(re.fullmatch(r'a[1-9abc]b', 'aab'))
print(re.fullmatch(r'a[abc1-9]b', 'aab'))
print(re.fullmatch(r'a[ac1-9b]b', 'aab'))
print(re.fullmatch(r'a[+*-]b', 'a-b'))
print(re.fullmatch(r'a[\dxyz]b', 'axb'))
print(re.fullmatch(r'a[\\dxyz]b', 'a\\b'))
# 8)[^字符集] - 匹配除了字符集以外的任意一个字符
"""
[^abc] - 匹配除了abc以外的任意一个字符
[^1-9] - 匹配除了1~9以外的任意一个字符
"""
print(re.fullmatch(r'a[^xyz]b', 'a=b')) # None
print(re.fullmatch(r'a[xyz^]b', 'a^b'))
print('============================检测符号===========================')
# 1) \b - 检测是否是单词结尾
"""
单词结尾 - 所有可以区分出两个不同单词的符号都是单词结尾,其中字符串开头和字符串结尾
用法: 检测\b所在的位置是否是单词结尾;不影响匹配的时候的字符串长度
"""
# 匹配一个长度是3的字符串,第一个字符是a,最后一个字符是b,中间是任意一个数字;并且要求b的后面是单词边界
re_str = r'a\db\b'
print(re.fullmatch(re_str, 'a7b'))
re_str = r'a\bxy'
print(re.fullmatch(re_str, 'a xy')) # None
re_str = r'abc\b\sxyz'
print(re.fullmatch(re_str, 'abc xyz'))
result = re.search(r'\d\d\d\b', 'ashdjfhow2378how 899kah989sf 789')
print(result)
# 2)^ - 检测字符串开头
# 判断^所在的位置是否是字符串开头
re_str = r'^\d\d\d'
print(re.fullmatch(re_str, '123'))
print(re.search(re_str, 'k898ahs237khhj'))
# 3)$ - 检测字符串结尾
re_str = r'\d\d\d$'
print(re.search(re_str, '123k898ahs237khhj990'))
re_str = r'^\d\d\d\d\d$'
print('=========================匹配次数=======================')
# 1) ? - 匹配0次或1次
"""
x? - x出现0次或1次
\d? - 任意数字出现0次或1次
[a-z]? - 小写字母出现0次或1次
"""
re_str = r'ax?b'
print(re.fullmatch(re_str, 'ab'))
print(re.fullmatch(re_str, 'axb'))
print(re.fullmatch(re_str, 'axxb')) # None
# 2) * - 匹配0次或多次
re_str = r'a\d*b' # r'a\d\d...\d\db'
print(re.fullmatch(re_str, 'ab'))
print(re.fullmatch(re_str, 'a2b'))
print(re.fullmatch(re_str, 'a12b'))
print(re.fullmatch(re_str, 'a1272937928329b'))
# 3) + - 匹配1次或多次
re_str = r'a\d+b'
print(re.fullmatch(re_str, 'ac')) # None
print(re.fullmatch(re_str, 'a2b'))
print(re.fullmatch(re_str, 'a12b'))
print(re.fullmatch(re_str, 'a1272937928329b'))
# 4){}
"""
{N} - 匹配N次
{M,N} - 匹配M到N次: ? -> {0,1}
{M,} - 匹配至少M次 * -> {0,} + -> {1,}
{,N} - 匹配最多N次
"""
re_str = r'a\d{5}b'
print(re.fullmatch(re_str, 'a78988b'))
print(re.fullmatch(re_str, 'a7898b')) # None
print(re.fullmatch(re_str, 'a789880b')) # None
re_str = r'a\d{3,5}b'
print(re.fullmatch(re_str, 'a78988b'))
print(re.fullmatch(re_str, 'a7898b'))
print(re.fullmatch(re_str, 'a789880b')) # None
# 练习: 写一个正则表达式判断输入的内容是否是整数
# 123 -> 成功! 123a -> 失败! -123 -> 成功! --123 -> 失败! +123 -> 成功
re_str = r'[+-]?[1-9]\d*'
四、正则表达式2
1.贪婪和非贪婪
匹配次数不确定的时候有贪婪和非贪婪两种状态
?,*
,+,{M,N},{,N},{M,} - 默认是贪婪的
??,*
?,+?,{M,N}?,{,N}?,{M,}? - 非贪婪
贪婪 - 在能匹配成功的前提下,尽可能多的匹配
非贪婪 - 在能匹配成功的前提下,尽可能少的匹配
re_str = r'\d{3,5}'
print(re.search(re_str, 'abc2732939333====')) # match='27329'
re_str = r'\d{3,5}?'
print(re.search(re_str, 'abc2732939333====')) # match='273'
re_str = r'a\d{3,5}?b'
print(re.search(re_str, 'a7283b238kk====')) # match='a7283b'
re_str = r'\d+'
print(re.search(re_str, 'abc2732939333====')) # match='2732939333'
re_str = r'a.+b'
print(re.search(re_str, '==a12xb67yusb0293===')) # match='a12xb67yusb'
re_str = r'a.+?b'
print(re.search(re_str, '==a12xb67yusb0293===')) # match='a12xb'
2.分之和分组
1)| - 分之:
正则1|正则2 - 先让正则1去匹配,如果匹配失败,再用正则2匹配;只要两个当中有一个能匹配成功,就成功
- () - 分组
(正则表达式) - 将正则表达式看成一个整体进行操作
整体控制次数:()匹配次数
重复:带分组的正则表达式\M - 在\M的位置重复前面第M个分组匹配到的内容
# 1) | - 分之
# 匹配三个数字或者三个字母的字符串
re_str = r'\d{3}|[a-zA-Z]{3}'
print(re.fullmatch(re_str, '890'))
# 匹配一个字符串: abc前是3个数字或者3个字母
# 123abc, uJhabc
re_str = r'\d{3}abc|[a-zA-Z]{3}abc'
# 2) () - 分组
# ab78hj90lo23
re_str = r'[a-z]{2}\d{2}[a-z]{2}\d{2}[a-z]{2}\d{2}'
# 9h8k9j8j7h6u5k....
re_str = r'(\d[a-z])+'
# 匹配一个字符串: abc前是3个数字或者3个字母
re_str = r'(\d{3}|[a-z]{3})abc'
print(re.fullmatch(re_str, 'mskabc'))
# abc123abc -成功! xab234xab - 成功! xyz123xyz -成功!
# abc123acb -失败! xab234sdk -失败!
# ab-ab abc-abc 123-123
re_str = r'(\d+)abc\1'
print(re.fullmatch(re_str, '234abc234'))
print(re.fullmatch(re_str, '12345abc12345'))
print(re.fullmatch(re_str, '234abc890')) # None
re_str = r'(\d+)([a-z]+)=\2'
print(re.fullmatch(re_str, '6kh=kh'))
re_str = r'(\d+)=\1([a-z]+)'
print(re.fullmatch(re_str, '123=123ioo'))
re_str = r'(\d{3})=(\1){2}'
print(re.fullmatch(re_str, '234=234234'))