1.对文件内容的增删改查
write,remove,write和seek,read等连用,read/readline/readlines, for line in file
with open(file_name, 'a', encoding='utf-8') as f:
read, write
r rt tb 只读
w wt wb 只写 清空
a at ab 只写 尾部追加
+ 读写
r+ rt+ rb+ 光标位置起始
a+ 光标位置末尾
read readline realines
循环 for line in files
写 write
seek 移动光标写 字节
write seek flush实时刷到硬盘
判断路径是否存在
exists = os.path.exists(file_path)
2.迭代器的含义
1、什么是迭代器
迭代器 指的是迭代取值的工具,迭代是一个重复的过程,
每次重复都是基于上一次的结果而继续的,
单纯的重复并不是迭代。
2、为何要有迭代器
迭代器是用来迭代取值的工具,而涉及到把多个值循环取出来的类型有:
列表、字符串、元组、字典、集合、打开的文件对象
实现一个简单的迭代取值功能(基于索引)
上面这种迭代取值的方式只适用于有索引的数据类型:列表,字符串,字典
为了解决基于索引迭代取值的局限性,python必须提供一种能够不依赖索引的取值方式,这就是迭代器
首先,了解一下“可迭代对象”:可以转换成“迭代器”的对象
可迭代对象:但凡内置有 _ iter _ 方法的都称之为可迭代对象
(字符串,列表,元组,字典,集合, 打开的文件,都是可迭代对象)
① 迭代器是一个对象,是一个可以记住遍历的位置的对象。
② 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。
③ 迭代器只能往前不会后退,迭代器有两个基本的用法iter()和next(),iter()是用来生成迭代器的,next()是用来访问迭代器的,也可以用for循环来遍历迭代器对象。
④ 字符串、列表、元组、集合可以用for循环来遍历,但它们并不是迭代器对象,不可以用next()是用来访问。
在python中,一切都是对象,对象的抽象是类,而对象的集合就是容器
所有的容器都是可以迭代的,你可以用for循环去迭代列表,集合,元组,字典试试
那把一个个元素找出来,用到的就是迭代器。用iter()可以创建一个迭代器。
迭代器提供一个next()方法,这个方法你每次调用的时候会给你返回下一个对象,或者StopIteration,也就是没有对象可以给你了
3.递归函数
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数
优点是定义简单,逻辑清晰。
理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰
使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致
栈溢出
特点
自己调用自己。
必须有一个明确的递归结束条件,称为递归出口
计算阶乘n! = 1 x 2 x 3 x ... x n,用函数fact(n)表示
def fact(n):
if n==1:
return 1
return n * fact(n - 1)
>>> fact(1)
>>> 1
>>> fact(5)
>>> 120
>>> fact(100)
4.匿名函数
lambda 参数:函数体
lambda x: 函数体
lambda x1,x2: 函数体
lambda *args, **kwargs: 函数体
def func(a1,a2):
return a1 + a2 + 100
foo = lambda a1,a2: a1 + a2 + 100 (和上面的def表达的意思一样,lambda只能一行)
5.内置函数考察 zip filter map
zip()函数
用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表.如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同。
传入参数:元组、列表、字典等迭代器
当zip()函数只有一个参数时
zip(iterable)从iterable中依次取一个元组,组成一个元组
元素个数相同
a = [1, 1, 1]
b = [2, 2, 2]
c = [3, 3, 3, 4]
print(list(zip(a, b, c))) # [(1, 2, 3), (1, 2, 3), (1, 2, 3)]
单个元素
lst = [1, 2, 3]
print(list(zip(lst))) # [(1,), (2,), (3,)]
利用*号操作符,可以将元组解压为列表
result = zip(v1, v2, v3) # 通过zip处理,一行一行输出
print(result) # <zip object at 0x000000000246EF88>
for item in result:
print(item)
一行一行输出
(11, 55, 10)
(22, 66, 20)
(33, 77, 30)
(44, 88, 40)
filter()
filter()函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件的元素组成的新列表。该函数接受两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判断,然后返回True或False。最后将返回True的元素放到新的列表中
语法
filter(function, iterable)
functon -- 判断函数
iterable -- 可迭代对象
返回列表
def is_odd(n):
return n % 2 == 0
lst = range(1, 11)
num = filter(is_odd, lst)
print(list(num)) # [2, 4, 6, 8, 10]
print(type(num)) # <class 'filter'>
map()
会根据提供的函数对指定序列做映射
第一个参数function以参数序列中的每一个元素调用function函数,返回包含每次function函数返回值的新列表
创建一个迭代器,使用来自的参数计算函数的每个迭代器。当最短的迭代器耗尽时停止
语法map(function, iterable, ...)
function -- 函数
iterable -- 一个或多个序列
listx = [1, 2, 3, 4, 5]
listy = [2, 3, 4, 5]
listz = [100, 100, 100, 100]
list_result = map(lambda x, y, z: x ** 2 + y + z, listx, listy, listz)
print(list(list_result))
[103, 107, 113, 121]
6.内置模块 time re json(总结用法)
json
序列化res = json.dumps(data) 数据类型 -> json 序列化生成一个字符串
反序列化data_list = json.loads(data_string) json格式 -> 数据类型
数据类型集合可以转为JSON,如果想要转,可以先将集合转化为支持的类型
time
import time
v1 = time.time() # 本地时间
v2 = time.timezone # 秒
datetime
v1 = datetime.now() # 当前本地时间
时间的加减
v2 = v1 + timedelta(days=140, minutes=5) # 当前时间加上140天零5分钟
datetime类型 + timedelta类型 可以加减, 但是datetime和datetime之间无法相加
v2 = datetime.utcnow() # 当前UTC时间
datetime之间相减,计算间隔时间(不能相加)!!!!
data = v1 - v2
v1 = datetime.strptime(text,'%Y-%m-%d') # %Y 年,%m,月份,%d,天。
时间戳
v1 = datetime.fromtimestamp(ctime) 时间戳格式 --> 转换为datetime格式
val = v1.timestamp() datetime格式 ---> 转换为时间戳格式
re
正则表达式
re.findall()
利用正则匹配QQ号码 [1-9]\d{4,}
身份证号码 data_list = re.findall("\d{17}[\dX]", text)
手机号 data_list = re.findall("1[3-9]\d{9}", text)
邮箱地址email_list = re.findall("\w+@\w+\.\w+",text)
- `^` 开始
- `$` 结束
一般用于对用户输入数据格式的校验比较多
先安装两个模块
pip3 install requests
pip3 install beautifulsoup4 # 提取每个评论
re模块
findall,获取匹配到的所有数据
match,从起始位置开始匹配,匹配成功返回一个对象,未匹配成功返回None
search,浏览整个字符串去匹配第一个,未匹配成功返回None
sub,替换匹配成功的位置
split,根据匹配成功的位置分割
finditer
7.函数的作用域
作用域,可以理解为一块空间,这块空间的数据是可以共享的。通俗点来说,作用域就类似于一个房子,房子中的东西归里面的所有人共享,其他房子的人无法获取
python是以函数为作用域
所以在函数内创建的所有数据,可以此函数中被使用,无法在其他函数中被使用
全局和局部
全局作用域中创建的变量称之为【全局变量,一般大写】,可以在全局作用域中被使用,也可以在其局部作用域中被使用
global关键字
默认情况下,在局部作用域对全局变量只能进行:读取和修改内部元素(可变类型),无法对全局变量进行重新赋值
如果想要在局部作用域中对全局变量重新赋值,则可以基于 `global`关键字实现
nolocal关键字
修改上一级作用域的变量的赋值
8.函数的参数形式& *args 和 **kwargs
函数执行传参时,传递的是内存地址
Python参数的这一特性有两个好处:
- 节省内存
- 对于可变类型且函数中修改元素的内容,所有的地方都会修改。可变类型:列表、
字典、集合。
函数的返回值是内存地址
在定义函数时,如果在括号中添加`变量`,我们称它为函数的形式参数
1. 形参
2. 实参
3. 位置传参
4. 关键字传参
######定义有三个参数的函数a1/a2/a3一般称为形式参数-形参 #####
def func(a1, a2, a3):
print(a1 + a2 + a3)
#执行函数并传入参数(执行函数传值时一般称为实际参数-实参)
func(11, 22, 33)
#执行函数并传入参数
func(9, 2, 103)
#执行函数
func(a1=99, a2=88, a3=1)
func(a1=99, a3=1, a2=88)
#执行函数(位置在前、关键在后)
func(10, a2=9, a3=10)
func(10, 9, a3=10)
func(1, 1, a3=20)
func(a1=1, a2=1, a3=20)
关键字传参(位置和关键混合时,关键字传参要在后面)
动态参数
def func(*args,**kwargs):
print(args,kwargs)
** 必须放在 * 的后面
数和动态参数混合时,动态参数只能放在最后。
形参固定,实参用`*和**`
参数是动态参数时,通过*或**传参时,会将数据循环添加到参数中(类似于拷贝一份
9.高阶函数
函数嵌套
嵌套引发的作用域问题 -- 基于内存和执行过程分析作用域
三句话搞定作用域:
- 优先在自己的作用域找,自己没有就去上级作用域。
- 在作用域中寻找值时,要确保此次此刻值是什么。
- 分析函数的执行,并确定函数`作用域链`。(函数嵌套)
闭包
装饰器
10.装饰器及其应用场景&闭包原理
闭包
简而言之就是将数据封装在一个包(区域)中,使用时再去里面取。(本质上 闭包是基于函数嵌套搞出来一个中特殊嵌套)
闭包应用场景1:封装数据防止污染全局
闭包应用场景2:封装数据封到一个包里,使用时在取
def task(arg):
def inner():
print(arg)
return inner
inner_func_list = []
for val in [11,22,33]:
inner_func_list.append( task(val) )
inner_func_list[0]() # 11
inner_func_list[1]() # 22
inner_func_list[2]() # 33
装饰器
在不修改原函数内容的前提下,通过@函数可以实现在函数前后自定义执行一些功能(批量操作会更有意义)。
- 实现原理:基于@语法和函数闭包,将原函数封装在闭包中,然后将函数赋值为一个新的函数(内层函数),执行函数时再在内层函数中执行闭包中的原函数。
-实现效果:可以在不改变原函数内部代码 和 调用方式的前提下,实现在函数执行和执行扩展功能。
-适用场景:多个函数系统统一在 执行前后自定义一些功能。
在以后编写一个网站时,如果项目共有100个页面,其中99个是需要登录成功之后才有权限访问,就可以基于装饰器来实现
基于第三方模块Flask(框架)快速写一个网站
python中支持特殊语法,在某个函数上方使用:
@函数名
def xxx():
pass
Python内部会自动执行 函数名(xxx) ,执行完之后,再讲结果赋值给 xxx。
xxx = 函数名(xxx)
装饰器示例(必须会,手写也需要会,面试经常遇到)
def outer(origin):
def inner(*args, **kwargs):
# 执行前
res = origin(*args, **kwargs) # 调用原来的func函数 必须用动态函数
# 执行后
return res
return inner # 无括号
@outer
def func():
pass
func()
其实,一般情况下大家不用functools也可以实现装饰器的基本功能,但后期在项目开发时,不加functools会出错(内部会读取`__name__`,且`__name__`重名的话就报错),所以在此大家就要规范起来自己的写法
import functools
def auth(func):
@functools.wraps(func)
def inner(*args, **kwargs):
"""巴巴里吧"""
res = func(*args, **kwargs) # 执行原函数
return res
return inner
11.迭代器和生成器(区别及其好处,特性)
迭代器
迭代器是一种可以被遍历的对象,它是实现了__next__( )方法的对象
迭代器从序列的第一个元素开始访问,直到所有的元素都被访问才结束
迭代器只能往后遍历,不能回溯
优点
使用迭代器不要求事先准备好整个迭代过程中的所有元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后元素可以不存在或者被销毁。因此迭代器适合遍历一些数量巨大甚至无限的序列
列表是可迭代的,但不是迭代器 列表变为迭代器使用 iter( )
迭代器取元素使用 next( )
使用__next( )__方法
使用for循环
生成器
在 Python 中,使用了 yield 的函数被称为生成器(generator)
如果一个函数,使用了yield语句,那么它就是一个生成器函数
调用一个生成器函数,返回的是一个迭代器对象
在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行
生成器实现斐波那契数列
生成器读取大文件
生成器一定是迭代器,但是迭代器不一定是生成器,因为创建一个迭代器只需要实现iter和next()方法就可以了,并不一定要使用yield实现。
生成器的唯一注意事项就是:生成器只能遍历一次
1、共同点
生成器是一种特殊的迭代器
2、不同点
a、语法上
生成器是通过函数的形式中调用 yield 或()的形式创建的
迭代器可以通过 iter() 内置函数创建
b、用法上
生成器在调用next()函数或for循环中,所有过程被执行,且返回值
迭代器在调用next()函数或for循环中,所有值被返回,没有其他过程或说动作。
1)生成器:
生成器本质上就是一个函数,它记住了上一次返回时在函数体中的位置。
对生成器函数的第二次(或第n次)调用,跳转到函数上一次挂起的位置。
而且记录了程序执行的上下文。
生成器不仅“记住”了它的数据状态,生成还记住了程序执行的位置。
2)迭代器
迭代器是一种可以被遍历的对象,它是实现了__next__( )方法的对象
迭代器从序列的第一个元素开始访问,直到所有的元素都被访问才结束
迭代器只能往后遍历,不能回溯
迭代器是一种支持next()操作的对象。它包含了一组元素,当执行next()操作时,返回其中一个元素。
当所有元素都被返回后,再执行next()报异常—StopIteration
生成器一定是可迭代的,也一定是迭代器对象
(3)区别:
①生成器是生成元素的,迭代器是访问集合元素的一种方式
②迭代输出生成器的内容
③迭代器是一种支持next()操作的对象
④迭代器(iterator):其中iterator对象表示的是一个数据流,可以把它看做一个有序序列,但我们不能提前知道序列的长度,只有通过nex()函数实现需要计算的下一个数据。可以看做生成器的一个子集。
为什么要使用生成器?因为效率。
使用生成器表达式取代列表推导式可以同时节省 cpu 和 内存(RAM)。
如果你构造一个列表(list)的目的仅仅是传递给别的函数,
比如 传递给tuple()或者set(), 那就用生成器表达式替代吧!
12.考核后补充总结
# 1.*args&**kwages区别
*args 称作为数组参数,只要你传入不小于 1 个参数,该函数都会接受,只能按照位置传参
**kwargs 称作为字典参数,采用 **kwargs 传递参数的时候,不能传递数组参数,只能按关键字传参
# 2.global nolocal的使用场景
global: 在局部访问全局中的内容
nonlocal: 在局部寻找外层函数中离他最近的那个变量,作用对象是外层变量(很显然就是闭包这种情况)
# 3.闭包使用场景
闭包应用场景1:封装数据防止污染全局
闭包应用场景2:封装数据封到一个包里,使用时在取。
闭包可以在很大程度上实现封装和代码复用
装饰器就是对闭包的使用
并行运算,基于多线程去下载视频
# 4.装饰器使用场景
装饰器实质上是代码复用
多个函数系统统一在 执行前后自定义一些功能例如:
打印日志
函数执行时间统计
执行函数前预备处理
执行函数后的清理功能
权限校验等场景
缓存
# 5.如果检查代码错误原因
多print()检测
看错误的提示原因,百度搜索,修改尝试
# 6.生成器和迭代器
迭代器
是一个更抽象的概念,任何对象,如果它的类有next方法和iter方法返回自己本身。对于string、list、dict、tuple等这类容器对象,使用for循环遍历是很方便的。在后台for语句对容器对象调用iter()函数,iter()是python的内置函数。iter()会返回一个定义了next()方法的迭代器对象,它在容器中逐个访问容器内元素,next()也是python的内置函数。在没有后续元素时,next()会抛出一个StopIteration异常
生成器(Generator)
是创建迭代器的简单而强大的工具。它们写起来就像是正规的函数,只是在需要返回数据的时候使用yield语句。每次next()被调用时,生成器会返回它脱离的位置(它记忆语句最后一次执行的位置和所有的数据值)
区别:生成器能做到迭代器能做的所有事,而且因为自动创建了__iter__()和next()方法,生成器显得特别简洁,而且生成器也是高效的,使用生成器表达式取代列表解析可以同时节省内存。除了创建和保存程序状态的自动方法,当发生器终结时,还会自动抛出StopIteration异常
迭代器遍历好多遍 生成器只能迭代一遍
应用:大数据的文件读取
利用生成器generator
迭代器进行迭代遍历:for line in file
# 7.os模块作用&sys模块作用
os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口;
sys模块负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境