什么是包
在python中,用来包裹模块的文件夹,
在python中,文件夹是可以当成包使用的,包并不是文件夹! !
注意:
在python中,如果一个文件夹中存在init .py这个模块文件的话,这个文件夹就是包
什么是模块
Xx.pv文件,保存是要执行或者使用代码
常见导包方式
import package.module
import package.module as aliasfrom package import module
from package import module as alias
from package.package. . . import module as alias
is是比较两个引用是否指向了同一个对象(地址引用比较)。
==是比较两个对象是否相等。(比较的数值)
赋值(基本数据类型)
主要的操作,栈内存的复制
浅拷贝
如果是一个列表:ls2 = ls.copy ()
浅拷贝对象,并不是把对象完整的拷贝,而是仅仅拷贝了第一层对象,
如果对象中存储子对象,那么子对象还是藕断丝连
深拷贝
深拷贝使用的递归的方式完成的拷贝,这样的,两个对象之间将没有任何关系
拷贝对象,而对象是存储在堆中的,拷贝堆内存
需要得到第二个一样的对象,复制拷贝对象的效率最高
python为了提供对象拷贝,专门为大家提供了一个copy模块
copy. copy#浅拷贝,相当于列表中copy方法
最佳实践:
1、需要将当前对象拷贝的时候,一般建议拷贝为浅拷贝,(效率高,内存占有少)
2、如果说,就是需要完全分离,请使用深拷贝
结论:
元组、字符串、数值这些不可变类型,所有深浅拷贝后,永远只有一份内存
注意特殊情况,如元组中的存在可变类型的元素
闭包是一种现象,是若数据类型编程语言所特有的现象。
Javascript (js)时时刻刻在使用闭包
概念:能够在函数内部调用其他函数变量的现象就闭包
函数包裹函数的现象,就叫做闭包
作用:让外层函数常驻内存,有可能垃圾无法回收
让局部变量全局化
什么是生成器?
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。 在 Python中,这种一边循环一边计算的机制,称为生成器:generator。
输出0到100的数字
>>> [x for x in range(101)]
[0, 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, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]
输出0到100的偶数
[ i for i in range(101) if i % 2 == 0]
99乘法表
[ i*j for i in rang(10) for j in rang(10)]
这个功能很强大 ,可以快速得到需要的列表
缺点:如果一个列表特别的庞大,这样所有的元素直接初始化到内存中,这样所有的元素直接初始化到内存中,引起大量无用元素占有内存问题
列表推导式 —> 生成器
[列表推导式] —> (列表推导式) #就会变成一个列表推导式
使用全局函数next,没调用一次next,返回下一个值,直到最后抛出异常也可以使用循环迭代generator
生成器对象也存在一个 next 魔方方法,等价于next全局函数
好处:节约内存
当列表生成时,需要大量代码来完成时,不可能使用列表推导式,一般使用函数完成,
斐波那契数列:
从第三个元素开始,每一个元素是前两个元素之和
#如果函数中使用yield关键字,那么这个函数的返回值就是一个生成器
def fibonacii2(num):
first,second = 1,1
index = 0
while index < num:
first,second = second,first + second
#如果函数中使用yield关键字,那么这个函数的返回值就是一个生成器
yield first
index += 1
if __name__ == '__main__':
res = fibonacii2(10)
print(res) #变成生成器
print(next(res)) #yield类似于return的作用
yield作用:
1、具有return的功能,能够返回一个函数的值
2、当一个函数出现yield,那么这个函数就不会调用执行,而是返回值是一个生成器,
next它的返回值,不断地返回被yield的值
3、yield值之后,会记住昂前位置,下一次next函数调用生成器的时候,会在记住的位置继续执行
略
应对高并发的一种很不错的方案
迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
以后需要迭代一个对象
from collections.abc import Iterable, Iterator
t = 对象
if isinsrance(t, Iterable):
for i in t:
#迭代对象
else:
print("该对象不可迭代")
from collections.abc import Iterable, Iterator(其中Iterable可迭代对象模块,Iterator迭代器模块)
在python,能够被全局函数next调用,并且返回下一个值的对象,就是迭代器。
可迭代对象不一定是迭代器,迭代器都是可迭代对象
凡是可作用于for循环的对象都是Iterable类型;
凡是可作用于next()函数的对象都是Iterator类型
可迭代对象不一定是迭代器,迭代器都是可迭代对象
>>> from collections.abc import Iterator
>>> ls = [1, 2, 3, 4, 5]
>>> ls_s = iter(ls)
>>> isinstance(ls, Iterator)
False
>>> isinstance(ls_s, Iterator)
True
>>> next(ls_s)
1
>>> next(ls_s)
2
>>> next(ls_s)
3
>>> next(ls_s)
4
>>> next(ls_s)
5
装饰器就是一个闭包函数,它能够@闭包名称装饰一个原有的函数,使得原有函数的功能更加强大
装饰器,功能就是在运行原来功能基础上,加上一些其它功能,比如权限的验证,比如日志的记录等等。不修改原
来的代码,进行功能的扩展。
比如java中的动态代理,python的注解装饰器
其实python的装饰器,是修改了代码。
OCP原则(open close protocol):对已有运行(稳定的)代码,不应该修改它,如果你增加新的功能,添加新的功能即可
1、定义一个闭包,闭包有一个默认的参数,是一个引用,该引用就是需要装饰的函数
2、一个需要在里面函数里面调用引用(函数),在调用之前写的代码就会被装饰在原函数之前,调用之后的代码会,会被装饰在原函数之后
1.引入日志
2.函数执行时间统计
3.执行函数前预备处理
4.执行函数后清理功能
5.权限校验等场景
6.异常的处理
7.缓存
使用了断点调试,追踪了下代码的运行流程,发现装饰器的运行原理
动态编程语言是高级程序设计语言的一个类别,在计算机科学领域已被广泛应用。它是一类在运行时可以改变其结构的语言
:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。动态语言目前非常具有活力。例如JavaScript便是一个动态语言,除此之外如PHP 、 Ruby . Python等也都属于动态语言,而c 、C++等语言则不属于动态语言。
python动态语言允许动态添加或者删除属性和方法
原理:以引用计数为主,以分代收集和标记清除为辅
正则表达式也叫做匹配模式(Pattern),它由一组具有特定含义的字符串组成,通常用于匹配和替换文本。
正则表达式,是一个独立的技术,很多编程语言支持正则表达式处理。
>>>import re
>>>s = "今天天气正好"
>>>res = re.match("今天", s)
>>>print(res)
>>>今天
>>>print(res.group())
>>>
<re.Match object; span=(0, 2), match='今天'>
[‘compile’, ‘copyreg’, ‘enum’, ‘error’, ‘escape’, ‘findall’, ‘finditer’, ‘fullmatch’, ‘functools’, ‘match’, ‘purge’, ‘search’, ‘split’, ‘sre_compile’, ‘sre_parse’, ‘sub’, ‘subn’, ‘template’]
compile #编译,可以改变正则表达式的规则
findall #查找所有,返回列表
finditer #查找所有,返回迭代器
match #以什么什么开头 匹配
search #查找,只能查一次
spilt #分割
sub #替换,类似于replace
. | 匹配任意符号(换行符不匹配 —> \n) |
---|---|
\d | 匹配数字 |
\w | 匹配所有的有效符号(大小写字母、数字、下划线、各国语言符号) |
\s | 匹配空格 |
^ | ^xxx 以xxx开头 |
$ | xxx$ 以xxx结尾 |
[ ] | 列举 比如:[0123456789] 等价于 \d 有效符号:[A-Za-z0-9_] |
\D | 匹配非数字 |
---|---|
\W | 特殊符号 |
\S | 非空白位 |
[^] | 列举反义 |
注意:1 和 [^] 的区别
前者表示:开头只能是[ ]内的字符,后者表示 :不取括号内的字符
在python的字符串中 \ 是有特殊含义的,如果要正常表示一个\,需要用两个 \ \ 来表示
在正则中,\是具有特殊含义的,要正常表示一个,则需要两个 \ \ 来表示
re.match(r" ",)
其中r表示只关心正则转义,不关心字符串转义
因此,建议大家以后再 写正则的时候,一定要在正则表达式前加上 r
* | 表示匹配任意位(可以使0个,也可以是1位,可以有n位) |
---|---|
+ | 至少一位(至少是1位,可以有n位) |
? | 0位或者1位 |
{n} | 有n位 |
{n,} | 至少n位 |
{m, n} | 表示m~n这个区间范围 |
在正则表达式中,使用圆括号()将正则中包裹起来,会形成正则匹配后的二次筛选
分组的最大好处,就是能够进行二次筛选
import re
s = "这是内容"
print(re.match(r"<\w+>.*\w+>", s)) # 可以匹配标签和内容(有弊端)
ss = "这是内容"
print(re.match(r"<\w+>.*\w+>", ss)) # 前后标签名不相同也可以匹配
print(re.match(r"<(\w+)>.*\1>", ss)) # 1代表需要和第一个括号内一样
sss = "这是内容"
print(re.match(r"<(\w+)>.*\1>", sss)) # 这样就可以了
运行结果如下:
<re.Match object; span=(0, 15), match='这是内容'>
<re.Match object; span=(0, 14), match='这是内容'>
None
<re.Match object; span=(0, 15), match='这是内容'>
贪婪模式 和 非贪婪模式 (懒惰模式)
在Python中正则默认是贪婪模式(个别语言中也可能是非贪婪模式),贪婪模式就是总会尝试匹配更多的字符。
非贪婪模式则反之,总是尝试匹配尽可能少的字符。
在*、? 、+、{m,n}后面加上?,可以将贪婪模式变成非贪婪模式。
*?
重复任意次,但尽可能少重复
+?
重复1次或更多次,但尽可能少重复
??
重复О次或1次,但尽可能少重复
{n, m} ?
重复n到m 次,但尽可能少重复
{n,} ?
重复n 次以上,但尽可能少重复
↩︎