python the third week

python the third week

文件操作

文件的概念

文件就是操作系统给用户操作的快捷方式。

打开文件的方式

方式1
open() 方法
Python open() 方法用于打开一个文件,并返回文件对象。
在对文件进行处理过程都需要使用到这个函数,如果该文件无法被打开,会抛出 OSError。
注意:使用 open() 方法一定要保证关闭文件对象,即调用 close() 方法。
open() 函数常用形式是接收两个参数:文件名(file)和模式(mode)。
eg:
f = open(文件路径,读写方式,encoding='utf8')
f.close()
方式2
使用with方法
with open (文件路径,读写方式,encoding='utf8') as 变量名:
ps:with上下文管理可以自己子代码结束后自动调用close方法关闭资源
open方法的第一个参数是文件路径 并且撬棍跟一些字母的组合会产生特殊的含义导致路径查找混乱 为了解决该问题可以在字符串的路径前面加字母r
D:\a\n\t
r'D:\a\n\t'
以后涉及到路径的编写 推荐加上r
with支持一次性打开多个文件
with open() as 变量名1,open() as 变量名2,open() as 变量名3:
子代码

文件的读写操作

'r' 只读模式:以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
1文件路径不存在:会直接报错
with open(r'b.txt','r',encoding='utf8')as f:
print(f.read())
2文件路径存在:正常读取文件的内容
with open(r'a.txt','r',encoding='utf8')as f:
print(f.read())
'w' 只写模式:打开一个文件只用于写入
1如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。
with open(r'a.txt','w',encoding='utf8')as f:
f.write('study hard and make progress every day\n')
f.write('study hard and make progress every day\n')
f.write('study hard and make progress every day\n')
2如果该文件不存在,创建新文件。
with open(r'a.txt','w',encoding='utf8')as f:
pass
'a' 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
1文件路径不存在:自动创建文件
with open(r'b.txt','a',encoding='utf8')as f:
pass
2文件路径存在:自动在末尾追加内容
with open (r'a.txt','a',encoding='utf8')as f:
f.write('很开心见到了你')
当我们在编写代码的时候 有些部分不知道写什么具体代码 但是也不能空着不写这个时候可以使用关键字。
pass
...
只补全语法不执行功能 本身没有任何的含义

文件的操作模式

t 文本模式
默认的模式,即上面的r w a其实全称是 rt wt at
1.只能操作文本文件.
2.读写都是以字符为单位。
3.需要指定encoding参数 如果不知道则会采用计算机默认的编码.
b 二进制模式(byte模式)
这个需要自己进行指定eg: rb wb ab
1.可以操作任意类型的文件.
2.读写都是以bytes为单位.
3.不需要指定encoding参数 因为它已经是二进制模式了 不需要编码.
二进制模式与文本模式针对文件路径是否存在的情况下 规律是一样的!!!

文件的诸多方法

1.read()
一次性读取文件内容 并且光标停留在文件末尾 继续读取则没有内容
并且当文件内容比较多的时候 该方法还可能会造成计算机内存溢出
括号内还可以填写数字 在文本模式下 表示读取几个字符如果未给定或为负则读取所有。
2for循环
一行行读取文件内容 避免内存溢出现象的产生
3readline([size])
读取整行,包括 "\n" 字符。
4readlines()
#['study hard and make progress every day\n', 'study hard and make progress every day\n', 'study hard and make progress every day\n', '很开心见到了你']
读取所有行并返回列表,若给定sizeint>0,返回总和大约为sizeint字节的行, 实际读取值可能比 sizeint 较大, 因为需要填充缓冲区。
5readline()
判断文件是否具备读数据的能力会返回true和false
6write()
将字符串写入文件,返回的是写入的字符长度。
7witeable()
判断文件是否具备写数据的能力true和false
8writeline()
向文件写入一个序列字符串列表,如果需要换行则要自己加入每行的换行符。
9flush()
刷新文件内部缓冲,直接把内部缓冲区的数据立刻写入文件, 而不是被动的等待输出缓冲区写入。

文件光标的移动

with open(r'a.txt','rb')as f:
print(f.read())
f.seek(0,0)
print(f.read())
f.seek(0,0)
print(f.read())
print(f.tell())#返回光标距离文件开头产生的字节数
seek(offset,whence)
offset 是位移量 以字节为单位
whence 是模式 0 1 2
0是基于文件开头:文本和二进制模式都可以用
1是基于当前位置:二进制模式可以用
2是基于文件末尾:二进制模式可以用
使用encode 编码
decode 解码

文件光标移动案例

import time
with open('access.log',mode='rb') as f:
f.seek(0,2)
while True:
line=f.readline()
if len(line) == 0:
# 没有内容
time.sleep(0.5)
else:
print(line.decode('utf-8'),end='')

计算机硬盘修改数据的原理

硬盘写数据可以看成是在硬盘上刻字 一旦需要修改中间内容 则需要重新刻字
因为刻过的字不可能从中间再分开
硬盘删除数据的原理
不是直接删除而是改变状态 等待后续数据的覆盖才会被真正删除

文件内容修改

# 文件a.txt内容如下:
张一蛋 山东 179 49 12344234523
李二蛋 河北 163 57 13913453521
王全蛋 山西 153 62 18651433422
'''
with open('a.txt', mode='r+', encoding='utf-8') as f:
# f.seek(9, 0)
f.seek(9) # seek模式就是0模式,第二个参数可以不指定
f.write('<男妇女主任>')
'''
# 文件a.txt内容修改以后:
张一蛋<男妇女主任>9 49 12344234523
李二蛋 河北 163 57 13913453521
王全蛋 山西 153 62 18651433422
文件对应的是硬盘空间,硬盘不能修改对应着文件本质也不能修改,
那我们看到文件的内容可以修改,是如何实现的呢?
大致的思路是将硬盘中文件内容读入内存,然后在内存中修改完毕后再覆盖回硬盘
具体的实现方式分为两种:

文件修改方式

文件修改方式1
# 实现思路:将文件内容发一次性全部读入内存,然后在内存中修改完毕后再覆盖写回原文件
# 优点: 在文件修改过程中同一份数据只有一份
# 缺点: 会过多地占用内存
with open('db.txt',mode='rt',encoding='utf-8') as f:
data=f.read()
with open('db.txt',mode='wt',encoding='utf-8') as f:
f.write(data.replace('kevin','SB'))
文件修改方式2
# 实现思路:以读的方式打开原文件,以写的方式打开一个临时文件,一行行读取原文件内容,修改完后写入临时文件...,删掉原文件,将临时文件重命名原文件名
# 优点: 不会占用过多的内存
# 缺点: 在文件修改过程中同一份数据存了两份
import os
with open('db.txt',mode='rt',encoding='utf-8') as read_f,\
open('.db.txt.swap',mode='wt',encoding='utf-8') as wrife_f:
for line in read_f:
wrife_f.write(line.replace('SB','kevin'))
os.remove('db.txt')
os.rename('.db.txt.swap','db.txt')

函数

函数前戏

name_list = ['jason', 'kevin', 'oscar', 'jerry']
def my_len():
count = 0
for i in name_list:
count += 1
print(count)
my_len()
循环
相同的代码在相同的位置反复执行
函数
相同的代码在不同的位置反复执行
ps:相同的代码不是真正一模一样而是可以通过传入的数据不同而做出不同的改变
函数相当于是工具(具有一定功能)
不用函数
修理工需要修理器件要用锤子 原地打造 每次用完就扔掉 下次用继续原地打造
用函数
修理工提前准备好工具 什么时候想用就直接拿出来使用
在程序中,具备某一功能的‘工具’指的就是函数,‘事先准备工具’的过程即函数的定义,‘拿来就用’即函数的调用。

函数的语法结构

1语法
Python 定义函数使用 def 关键字,一般格式如下:
def 函数名(参数列表):
函数体
1def: 定义函数的关键字;
2函数名:函数名指向函数内存地址,是对函数体代码的引用。函数的命名应该反映出函数的功能;
3括号:括号内定义参数,参数是可有可无的,且无需指定参数的类型;
4冒号:括号后要加冒号,然后在下一行开始缩进编写函数体的代码;
5"""文档描述""": 描述函数功能,参数介绍等信息的文档,非必要,但是建议加上,从而增强函数的可读性;
6函数体:由语句和表达式组成;
7return 值:定义函数的返回值,return是可有可无的。
参数是函数的调用者向函数体传值的媒介,若函数体代码逻辑依赖外部传来的参数时则需要定义为参函数
def my_min(x,y):
res=x if x < y else y
return res
否则定义为无参函数
def interactive():
user=input('user>>: ').strip()
pwd=input('password>>: ').strip()
return (user,pwd)

函数的定义与调用

1.函数在定义阶段只检测语法 不执行代码
def func():
pass
函数体为pass代表什么都不做,称之为空函数。定义空函数通常是有用的,因为在程序设计的开始,往往是先想好程序都需要完成什么功能,然后把所有功能都列举出来用pass充当函数体“占位符”,这将使得程序的体系结构立见,清晰且可读性强。
2.函数在调用阶段才会执行函数体代码
func()
3.函数必须先定义后调用
4.函数定义使用关键字def函数调用使用>>>:函数名加括号

函数的分类

1.空函数
函数体代码为空 使用的pass或者...补全的
空函数主要用于项目前期的功能框架搭建
def register():
"""注册功能"""
pass
2.无参函数
定义函数的时候括号内没有参数
def index():
print('from index function')
3.有参函数
定义函数的时候括号内写参数 调用函数的时候括号传参数
def func(a):
print(a)

函数的返回值

1.什么是返回值
调用函数之后返回给调用者的结果
2.如何获取返回值
变量名 赋值符号 函数的调用
res = func() # 先执行func函数 然后将返回值赋值给变量res
3.函数返回值的多种情况
3.1.函数体代码中没有return关键字 默认返回None
3.2.函数体代码有return 如果后面没有写任何东西还是返回None
3.3.函数体代码有return 后面写什么就返回什么
3.4.函数体代码有return并且后面有多个数据值 则自动组织成元组返回
3.5.函数体代码遇到return会立刻结束

函数的参数

形式参数
在函数定义阶段括号内填写的参数 简称'形参'
实际参数
在函数调用阶段括号内填写的参数 简称'实参'
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""
形参与实参的关系
形参类似于变量名 在函数定义阶段可以随便写 最好见名知意
def register(name,pwd):
pass
实参类似于数据值 在函数调用阶段与形参临时绑定 函数运行结束立刻断开
register('jason',123) 形参name与jason绑定 形参pwd与123绑定
"""
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

函数参数之位置参数

位置参数指的是按顺序定义的参数,需要从两个角度去看:
1位置形参
在定义函数时,按照从左到右的顺序依次定义形参,称为位置形参,凡是按照这种形式定义的形参都必须被传值
def funcl(a,b,c):pass 代码行只有一行可以直接写在冒号后面
2位置实参
在调用函数时,按照从左到右的顺序依次定义实参,称为位置实参,凡是按照这种形式定义的实参会按照从左到右的顺序与形参一一对应
funcl(1,2,3)
eg:
def a(a,b):
print(a,b)
a(1,2) # 按照位置一一对应传值
a(1) # 少一个会报错
a(1,2,3) # 多一个也会报错
a(b=1,a=2) # 关键字传值(使用变量名定义)
a(b=1,2)# 关键字传参一定要跟在位置传参的后面 报错
a(2,b=1) # 可以
a(1,a=2,b=3)# 同一个形参在调用的时候不能多次赋值
name='jason'
pwd=123
a(name,pwd) # 实参没有固定的定义 可以传数据值 也可以传绑定了数据值的变量名
a(a=name,b=pwd) # 实参没有固定的定义 可以传数据值 也可以传绑定了数据值的变量名
口诀:
越短的越简单的越靠前
越长的越复杂的越靠后
但是遇到下列的情况除外
同一个形参在调用的时候不能多次赋值

默认参数

本质其实就是关键字形参(关键字实参上述内容已经讲了)
别名叫默认参数:提前就已经给了 用户可以不传 也可以传
定义时应遵循:
默认参数的定义也遵循短的简单的靠前 长的复杂的靠后。
def a(name,age,gender='male'):
print("""
--------学员信息----------
姓名:{name}
年龄:{age}
性别:{gender}
-------------------------
""")
a('tom',18)
a('jerk',28,'female')
a('jerry',10,gender="female")

可变长形参

一个函数能处理比当初声明时更多的参数。这些参数叫做可变长参数
基本语法如下:
def functionname([formal_args,] *var_args_tuple ):
"函数_文档字符串"
function_suite
return [expression]
加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。
def a(*args):
print(args)
a() # ()
a(1) # (1,)
a(1, 2) # (1, 2)
def a(**kwargs):
print(kwargs)
a() # {}
a(a=1) # {'a': 1}
a(a=1, b=2) # {'a': 1, 'b': 2}
混合使用:
def a(*args, **kwargs):
print(args, kwargs)
a() # () {}
a(a=1) # () {'a': 1}
a(a=1, b=2, c=3) # () {'a': 1, 'b': 2, 'c': 3}
a(a=1, b=2, c=3, x='jason', y='kevin') # () {'a': 1, 'b': 2, 'c': 3, 'x': 'jason', 'y': 'kevin'}
def a(n, *args, **kwargs):
print(n, args, kwargs)
# a() # 报错至少有一个b参数
a(1, 2, 3) # 1 (2, 3) {}
a(111, a=1, b=2, c=3) # 111 () {'a': 1, 'b': 2, 'c': 3}
a(n=111, a=1, b=2, c=3) # 111 () {'a': 1, 'b': 2, 'c': 3}
a(a=1, b=2, c=3, n=111) # 111 () {'a': 1, 'b': 2, 'c': 3}
a(1, 2, 3, a=1, b=2, c=3) # 1 (2, 3) {'a': 1, 'b': 2, 'c': 3}
注意:
由于*和**在函数的形参中使用频率很高 后面跟的变量名推荐使用
*args
**kwargs
def index(*args,**kwargs):pass

可变长实参

def a(a, b, c):
print(a, b, c)
l1 = [123, 321, 132]
# 方法1索引取值(不推荐)
a(l1[0], l1[1], l1[2]) # 123 321 132
# 方法二用*来进行赋值
a(*l1) # 123 321 132
l2 = ['aaa', 'bbb', 'ccc']
a(*l2) # aaa bbb ccc
s1 = 'tom'
a(*s1) # t o m
set1 = {123, 1231, 321} # 集合不能重复否则会报错
a(*set1) # 321 123 1231
dic1 = {'username': 'jason', 'pwd': 123, 'age': 18}
a(*dic1) # username pwd age取的是键
a(*dic1.values()) # jason 123 18取的是值
*在实参中
类似于for循环 将所有循环遍历出来的数据按照位置参数一次性传给函数
def user_info(name, password, age):
print(name, password, age)
d1 = {'name': 'mingming', 'password': 123, 'age': 18}
user_info(name=d1['name'], password=d1['password'], age=d1['age']) # mingming 123 18
user_info(*d1.values()) # mingming 123 18
user_info(**d1) # mingming 123 18
user_info(name='mingming', password=123, age=18) # mingming 123 18
**在实参中
将字典打散成关键字参数的形式传递给函数
def a(*args, **kwargs):
print(args, kwargs)
a(*[11, 22, 33, 44]) # (11, 22, 33, 44) {}
a(*(11, 22, 33, 44)) # (11, 22, 33, 44) {}

命名关键参数

形参必须按照关键字参数传值>>>:命名关键字参数
def a(name, *args, gender='male', **kwargs):
print(name, args, gender, kwargs)
a('mingming', 1, 2, 3, 4, 5, a=1, b=2) # mingming (1, 2, 3, 4, 5) male {'a': 1, 'b': 2}
a('leilei', 1, 2, 2, 2, gender='female', a=1, b=2) # leilei (1, 2, 2, 2) female {'a': 1, 'b': 2}

名称空间与作用域

名称空间

name = 'jason'
1.申请内存空间存储jason
2.给jason绑定一个变量名name
3.后续通过变量名name就可以访问到jason
名称空间即存放名字与对象映射/绑定关系的地方。对于x=3,Python会申请内存空间存放对象3,然后将名字x与3的绑定关系存放于名称空间中,del x表示清除该绑定关系。
在程序执行期间最多会存在三种名称空间

1.内置名称空间

py文件执行过程中产生的名字都会存放于该名称空间中
import sys #模块名sys
x=1 #变量名x
if x == 1:
y=2 #变量名y
def foo(x): #函数名foo
y=1
def bar():
pass
Class Bar: #类名Bar
pass

名称空间存活周期及作用域

存活周期
内置名称空间
python解释器启动则创建 关闭则销毁
全局名称空间
py文件执行则创建 运行结束则销毁
局部名称空间
函数体代码运行创建 函数体代码结束则销毁(类暂且不考虑)
作用域
内置名称空间
解释器级别的全局有效
全局名称空间
py文件级别的全局有效
局部名称空间
函数体代码内有效

名字的查找顺序

1在python文件中相互独立的方法的命名空间默认是不能够互相访问的
def a():
name = 'jason'
print(age)
def b():
age = 18
print(name)
2局部空间嵌套
先从自己的局部名称空间查找 之后由内而外依次查找
x = '123321'
def func1():
x = 1
def func2():
x = 2
def func3():
x = 3
print(x)#3
func3()
print(x)#2
func2()
print(x)#1
func1()
print(x)#123321

global与nonlocal

1 global关键字:
在函数中,如果想给全局变量赋值,则需要用关键字global声明。
eg:
money = 666
def index():
global money
money = 123
index()
print(money)#123
2 nonlocal关键字:
nonlocal只能在封装函数中使用,在外部函数先进行声明,在内部函数进行nonlocal声明
def index():
name = 'jason'
def inner():
nonlocal name
name = 'kevin'
inner()
print(name)
index()

函数名的多种用法

函数名其实绑定的也是一块内存地址 只不过该地址里面存放的不是数据值而是一段代码 函数名加括号就会找到该代码并执行.
1.函数名可以当作变量名赋值
def index():pass
res = index
res()
2函数名可以当作函数的参数
def index():
print('from index')
def func(a):
print(a)
a()
func(index)
3函数名可以当作函数返回值
def index():
print('from index')
def func():
print('from func')
return index
res = func()
print(res)
res()
4函数名可以当做容器类型(可以存放多个数据的数据类型)的数据。
def reginster():
print('注册功能')
def login():
print('登录功能')
def withdraw():
print('提现功能')
def transfer():
print('转账功能')
def shopping():
print('购物功能')
#定义功能编号与功能的对应关系
fun_dict={
'1':reginster,
'2':login,
'3': withdraw,
'4': transfer,
'5': shopping
}
while 1:
print("""
1.注册功能
2.登录功能
3.提现功能
4.转账功能
5.购物功能
""")
choice =input('>>>:').strip()
if choice in fun_dict:
fun_name=fun_dict.get(choice)
fun_name()
else:
print('功能编号不存在')

函数闭包

基于函数对象的概念,可以将函数返回到任意位置去调用,但作用域的关系是在定义完函数时就已经被确定了的,与函数的调用位置无关。
定义在函数内部的函数 并且用到了外部函数名称空间中的名字
1.定义在函数内容
2.用到外部函数名称空间中的名字
def index():
name = 'jason'
def inner():
print(name)
两种为函数体传值的方式,一种是直接将值以参数的形式传入,另外一种就是将值包给函数.
方式1
def register(name,age):
print(f"""
姓名:{name}
年龄:{age}
""")
register('jason', 18)
register(name='jason', age=18)
方式2
def outer(name, age):
# name = 'jason'
# age = 18
def register():
print(f"""
姓名:{name}
年龄:{age}
""")
return register
res = outer('jason', 18)
res()
res = outer('kevin', 28)
res()

装饰器简介

1.概念
装饰器就是在不修改被装饰器对象源代码以及调用方式的前提下为被装饰对象添加新功能。
2本质
装饰器指的定义一个函数,该函数是用来为其他函数添加额外的功能.就是拓展原来函数功能的一种函数
3口诀
对修改封闭 对扩展开放
4操作
时间相关操作
import time
print(time.time())#1665478515.6596327时间戳:距离1970-01-01 00:00:00所经历的秒数
time.sleep(3)
print('123321')
count = 0
start_time=time.time()
while count<500:
print('qqqq')
count += 1
end_time =time.time()
print('循环消耗的时间:', end_time - start_time)

装饰器推导流程

1直接在调用index函数后面添加后代
import time
def index():
time.sleep(3)
print('from index')
def home():
time.sleep(1)
print('from home')
start_time = time.time()
index()
end_time = time.time()
print('函数index的执行时间为>>>:', end_time-start_time)
2index调用的地方较多 代码不可能反复拷贝>>>:相同的代码需要在不同的位置反复执行>>>:函数
import time
def index():
time.sleep(3)
print('from index')
def home():
time.sleep(1)
print('from home')
def get_time():
start_time = time.time()
index()
end_time = time.time()
print('函数index的执行时间为>>>:', end_time - start_time)
get_time()
3..函数体代码写死了 只能统计index的执行时间 如何才能做到统计更多的函数运行时间 直接传参变换统计的函数
import time
def index():
time.sleep(3)
print('from index')
def home():
time.sleep(1)
print('from home')
def get_time(xxx):
start_time = time.time()
xxx()
end_time = time.time()
print('函数的执行时间为>>>:', end_time - start_time)
get_time(index)
get_time(home)
4.虽然实现了一定的兼容性 但是并不符合装饰器的特征 第一种传参不写 只能考虑闭包
import time
def index():
time.sleep(3)
print('from index')
def home():
time.sleep(1)
print('from home')
def outer(xxx):
xxx = index
def get_time():
start_time = time.time()
xxx()
end_time = time.time()
print('函数的执行时间为>>>:', end_time - start_time)
return get_time
res = outer(index)
res()
res1 = outer(home)
res1()
5.调用方式还是不对 如何变形>>>:变量名赋值绑定
import time
def index():
time.sleep(3)
print('from index')
def home():
time.sleep(1)
print('from home')
def outer(xxx):
def get_time():
start_time = time.time()
xxx()
end_time = time.time()
print('函数的执行时间为>>>:', end_time - start_time)
return get_time
res = outer(index) # 赋值符号的左边是一个变量名 可以随意命名
res1 = outer(index)
res2 = outer(index)
jason = outer(index)
index = outer(index)
index()
home = outer(home)
home()
6.上述装饰器只能装饰无参函数 兼容性太差
import time
def func(a):
time.sleep(0.1)
print('from func', a)
def func1(a,b):
time.sleep(0.2)
print('from func1', a, b)
def func2():
time.sleep(0.3)
print('from func2')
func(123)
def outer(xxx):
def get_time(a, b):
start_time = time.time()
xxx(a, b)
end_time = time.time()
print('函数的执行时间为>>>:', end_time - start_time)
return get_time
func1 = outer(func1)
func1(1, 2)
func = outer(func)
func(1)
func2 = outer(func2)
func2()
7.被装饰的函数不知道有没有参数以及有几个参数 如何兼容
import time
def func(a):
time.sleep(0.1)
print('from func', a)
def func1(a,b):
time.sleep(0.2)
print('from func1', a, b)
def outer(xxx):
def get_time(*args, **kwargs): # get_time(1,2,3) args=(1,2,3)
start_time = time.time()
xxx(*args, **kwargs) # xxx(*(1,2,3)) xxx(1,2,3)
end_time = time.time()
print('函数的执行时间为>>>:', end_time - start_time)
return get_time
func = outer(func)
func(123)
func1 = outer(func1)
func1(1, 2)
8.如果被装饰的函数有返回值
import time
def func(a):
time.sleep(0.1)
print('from func', a)
return 'func'
def func1(a,b):
time.sleep(0.2)
print('from func1', a, b)
return 'func1'
def outer(xxx):
def get_time(*args, **kwargs):
start_time = time.time()
res = xxx(*args, **kwargs)
end_time = time.time()
print('函数的执行时间为>>>:', end_time - start_time)
return res
return get_time
func = outer(func)
res = func(123)
print(res)

装饰器模板

在特定条件下为某些函数再不改动函数体的时候为函数新添加一些功能,这就是装饰器
# 务必掌握
def outer(func):
def inner(*args, **kwargs):
# 执行被装饰对象之前可以做的额外操作
res = func(*args, **kwargs)
# 执行被装饰对象之后可以做的额外操作
return res
return inner

装饰器语法糖

\@是一个装饰器,针对函数,起调用传参的作用。
有修饰和被修饰的区别,作为一个装饰器,用来修饰紧跟着的函数(可以是另一个装饰器,也可以是函数定义)。
def outer(func_name):
def inner(*args, **kwargs):
print('执行被装饰对象之前可以做的额外操作')
res = func_name(*args, **kwargs)
print('执行被装饰对象之后可以做的额外操作')
return res
return inner
"""
语法糖会自动将下面紧挨着的函数名当做第一个参数自动传给@函数调用
"""
@outer # func = outer(func)
def func():
print('from func')
return 'func'
@outer # index = outer(index)
def index():
print('from index')
return 'index'
func()
index()

多层语法糖

def outter1(func1):
print('加载了outter1')
def wrapper1(*args, **kwargs):
print('执行了wrapper1')
res1 = func1(*args, **kwargs)
return res1
return wrapper1
def outter2(func2):
print('加载了outter2')
def wrapper2(*args, **kwargs):
print('执行了wrapper2')
res2 = func2(*args, **kwargs)
return res2
return wrapper2
def outter3(func3):
print('加载了outter3')
def wrapper3(*args, **kwargs):
print('执行了wrapper3')
res3 = func3(*args, **kwargs)
return res3
return wrapper3
@outter1 # outter1拿到wrapper2,outter1的上层没有语法糖,index = outter1(wrapperw)
@outter2 #outter2拿到wrapper3,wrapper3 = outter3(index)
@outter3 #@outter3紧贴index(),outter3调用index(),返回wrapper3,所以wrapper3 = outter3(index)
def index():
print('from index')
多层语法糖加载的顺序从下往上执行,
每次执行之后如果上面还有语法糖 则直接将返回值函数名传给上面的语法糖
如果上面没有语法糖了 则变形 index = outter1(wrapper2)

有参装饰器

def outter(x):
def outter1(func):
def wrapper(*args,*kwargs):
res = func(*args,**kwargs)
print(x)
return res
return wrapper
return outter1
# 通过第三层进行传值,使得有参装饰器可以使用其他参数,实现其他功能。
@outter('a')
#可以被看做
#f1 = outter1(f1)
#f1 = wrapper(*args,**kwargs)

装饰器模板

最常用的无参装饰器
def outer(func_name):
def inner(*args, **kwargs):
res = func_name(*args, **kwargs)
return res
return inner
@outer
def index():
pass
不常用的有参装饰器
def outer_plus(mode):
def outer(func_name):
def inner(*args, **kwargs):
res = func_name(*args, **kwargs)
return res
return inner
return outer
@outer_plus('MySQL')
def func():
pass

装饰器修复技术

由来:使用装饰器有一个小毛病,就是想要查看被装饰器的注释或者名字时,比如使用如下方法时:
print(help(index)) # 查看函数的注释
print(index.__name__) # 查看函数名字符串形式
结果看到的注释不是被装饰器的注释,而是装饰器里面的内部闭包函数的注释。
查看到的函数名字也是装饰器内部函数的名字,调用函数的时候,想看函数的名字和注释,看到的却不是对的。
基于以上情况,Python提供了解决方案,叫做装饰器修复技术。
# def index():
# """index函数 非常的牛"""
# pass
# help(index)
# help(len)
from functools import wraps
def outer(func_name):
@wraps(func_name) # 仅仅是为了让装饰器的效果更加逼真 平时可以不写
def inner(*args, **kwargs):
"""我是inner 我擅长让人蒙蔽"""
res = func_name(*args, **kwargs)
return res
return inner
@outer
def func():
"""我是真正的func 我很强大 我很牛 我很聪明"""
pass
# help(func)
# print(func)
func()

递归函数

递归的特点:
函数内部自己调用自己。
必须有出口。
1 必须有一个明确的结束条件。
2 每次进入更深一层递归时,问题规模(计算量)相比上次递归都应有所减少。
3 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出),此时程序会抛出错误:超出最大递归深度。
递推:像上边递归实现所拆解,递归每一次都是基于上一次进行下一次的执行,这叫递推。
回溯:则是在遇到终止条件,则从最后往回返一级一级的把值返回来,这叫回溯。
eg:
#1直接调用
# def index():
# print('from index')
# index()
# index()
# 间接
# def index():
# print('from index')
# func()
#
# def func():
# print('from func')
# index()
#
# func()
'''最大递归深度:python解释器添加的安全措施'''
# count = 0
# def index():
# global count
# count += 1
# print(count)
# index()
# index()
'''官网提供的最大递归深度为1000 我们在测试的时候可能会出现996 997 998'''
2.递归函数
"""
get_age(5) = get_age(4) + 2
get_age(4) = get_age(3) + 2
get_age(3) = get_age(2) + 2
get_age(2) = get_age(1) + 2
get_age(1) = 18
"""
def get_age(n):
if n == 1:
return 18
return get_age(n-1) + 2
res = get_age(5)
print(res)

算法简介及二分法

1.什么是算法
算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。如果一个算法有缺陷,或不适合于某个问题,执行这个算法将不会解决这个问题。不同的算法可能用不同的时间,空间或效率来完成同样的任务。一个算法的优劣可以用空间复杂度与时间复杂度来衡量。
2算法的特征
一个算法应该具有以下五个重要的特征:
有穷性:算法的有穷性是指算法必须能在执行有限个步骤之后终止;
确切性:算法的每一步骤必须有确切的定义;
输入项:一个算法有0个或多个输入,以刻画运算对象的初始情况,所谓0个输入是指算法本身定出了初始条件;
输出项:一个算法有一个或多个输出,以反映对输入数据加工后的结果。没有输出的算法是毫无意义的;
可行性:算法中执行的任何计算步骤都是可以被分解为基本的可执行的操作步骤,即每个计算步骤都可以在有限时间内完成(也称之为有效性)。
3算法应用场景
推荐算法(抖音视频推送 淘宝商品推送)
成像算法(AI相关)......
几乎涵盖了我们日常生活中的方方面面
4算法部门
不是所有的互联网公司都养得起算法部分 只有大型互联网公司才有
算法部门类似于药品研发部分.
5二分法
是算法中最简单的算法 甚至都称不上是算法
二分法使用要求:
待查找的数据集必须有序
二分法的缺陷:
针对开头结尾的数据 查找效率很低
常见算法的原理以及伪代码
二分法、冒泡、快拍、插入、堆排、桶排、数据结构(链表 约瑟夫问题 如 何链表是否成环)
l1 = [12, 21, 32, 43, 56, 76, 87, 98, 123, 321, 453, 565, 678, 754, 812, 987, 1001, 1232]
def get_middle(l1,target_num):
if len(l1)==0:
print('没找到')
return
minddle_index=len(l1)//2
if target_num>l1[minddle_index]:
right_l1=l1[minddle_index+1:]
print(right_l1)
return get_middle(right_l1,target_num)
elif target_num<l1[minddle_index]:
left_l1=l1[:minddle_index]
print(left_l1)
return get_middle(left_l1,target_num)
else:
print('恭喜你 找到了!!!')
get_middle(l1,22)
冒泡
快拍
插入
堆排
桶排
数据结构(链表 约瑟夫问题 如 何链表是否成环)

三元表达式

Python是示例可以看出,Python的三元表达式格式如下:
条件为真时的结果 if 判段的条件 else 条件为假时的结果
适用场景:变量赋值时,要做条件判断时,简化代码时使用。
a=1
b=2
方法1
c='qqq' if a<b else 'bbb'
print(c)#qqq
数据值1 if 条件 else 数据值2
条件成立则使用数据值1 条件不成立则使用数据值2
当结果是二选一的情况下 使用三元表达式较为简便
并且不推荐多个三元表达式嵌套
方法2
print({True: 'qqq', False: 'bbb'}[a > b])
模板:
{True:数据值1, False: 数据值2}[判断条件]
条件成立则使用数据值1 条件不成立则使用数据值2
方法3
print(('qqq','bbb')[a > b])
模板:
(数据值1,数据值2)[判断条件]
条件不成立则使用数据值1条件成立则使用数据值2

各种生成式/表达式/推导式

Python 推导式是一种独特的数据处理方式,可以从一个数据序列构建另一个新的数据序列的结构体。
Python 支持各种数据结构的推导式:
列表(list)推导式
字典(dict)推导式
集合(set)推导式
元组(tuple)推导式
列表推导式格式:
[表达式 for 变量 in 列表]
[out_exp_res for out_exp in input_list]
或者
[表达式 for 变量 in 列表 if 条件]
eg:
[out_exp_res for out_exp in input_list if condition]
name_list=['jason','xiaoming','xiaoghong','xiaolan']
# 给列表中所有人名的后面加上_NB的后缀
#for 循环
new_list=[]
for name in name_list:
name=f'{name}_NB'
new_list.append(name)
print(new_list)#['jason_NB', 'xiaoming_NB', 'xiaoghong_NB', 'xiaolan_NB']
#列表推导式
new_list1=[name +'_NB' for name in name_list]
print(new_list1)#['jason_NB', 'xiaoming_NB', 'xiaoghong_NB', 'xiaolan_NB']
#复杂情况
new_list11=[name +'_NB' for name in name_list if name=='jason']
print(new_list11)#['jason_NB']
new_list111=['嘻嘻'if name=='jason' else'哈哈' for name in name_list if name !='xiaoghong']
print(new_list111)#['嘻嘻', '哈哈', '哈哈']
字典推导式:
字典推导基本格式:
{ key_expr: value_expr for value in collection }
{ key_expr: value_expr for value in collection if condition }
# 将列表中各字符串值为键,各字符串的长度为值,组成键值对
eg:
s1='hello word'
for i,j in enumerate(s1):
print(i,j)
d1={i:j for i,j in enumerate('hello')}
print(d1)#{0: 'h', 1: 'e', 2: 'l', 3: 'l', 4: 'o'}
# enumerate
enumerate() 方法的语法:
enumerate(sequence, [start=0])
sequence -- 一个序列、迭代器或其他支持迭代对象。
start -- 下标起始位置。
enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。
集合推导式:
集合推导式基本格式:
{ expression for item in Sequence }
{ expression for item in Sequence if conditional }
eg:
res = {i for i in 'hello'}
print(res)#{'e', 'h', 'l', 'o'}
元组推导式
元组推导式可以利用 range 区间、元组、列表、字典和集合等数据类型,快速生成一个满足指定需求的元组。
元组推导式基本格式:
(expression for item in Sequence )
(expression for item in Sequence if conditional )
元组推导式和列表推导式的用法也完全相同,只是元组推导式是用 () 圆括号将各部分括起来,而列表推导式用的是中括号 [],另外元组推导式返回的结果是一个生成器对象。
例如,我们可以使用下面的代码生成一个包含数字 1~9 的元组:
a=(b for b in range(1,10))
print(tuple(a))#(1, 2, 3, 4, 5, 6, 7, 8, 9)

匿名函数

Python 使用 lambda 来创建匿名函数。
所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数
lambda 只是一个表达式,函数体比 def 简单很多
lambda 的主体是一个表达式,而不是一个代码块。仅仅能在 lambda 表达式中封装有限的逻辑进去。
lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
虽然 lambda 函数看起来只能写一行,却不等同于 C 或 C++ 的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
语法
lambda 函数的语法只包含一个语句,如下:
lambda [arg1 [,arg2,.....argn]]:expression
设置参数 a 加上 10:
实例
x = lambda a : a + 10
print(x(5))
以上实例输出结果:
15
以下实例匿名函数设置两个参数:
实例(Python 3.0+)
#!/usr/bin/python3
# 可写函数说明
sum = lambda arg1, arg2: arg1 + arg2
# 调用sum函数
print ("相加后的值为 : ", sum( 10, 20 ))
print ("相加后的值为 : ", sum( 20, 20 ))
以上实例输出结果:
相加后的值为 : 30
相加后的值为 : 40
我们可以将匿名函数封装在一个函数内,这样可以使用同样的代码来创建多个匿名函数。
以下实例将匿名函数封装在 myfunc 函数中,通过传入不同的参数来创建不同的匿名函数:
实例
def myfunc(n):
return lambda a : a * n
mydoubler = myfunc(2)
mytripler = myfunc(3)
print(mydoubler(11))
print(mytripler(11))
以上实例输出结果:
22
33

内置函数

1map()映射
map(func,iterable),其中func为函数名,可为lambda匿名函数,iterable为可迭代对象。此函数会将可迭代对象中的每一位元素作为参数传递到func中,并将func的计算结果加入到新列表内,map()返回的是一个包含所有结果的新列表。
eg:
l=[1,2,3,4,5]
res=map(lambda x:x+1,l)
print(list(res))#[2, 3, 4, 5, 6]
2.max()\min()
ll=[11, 22, 33, 44]
res=max(ll)
print(res)#44
res1=min(ll)
print(res1)#11
d1 = {
'zj': 100,
'jason': 8888,
'berk': 99999999,
'oscar': 1
}
def func(a):
return d1.get(a)
# res = max(d1, key=lambda k: d1.get(k))
res = max(d1, key=func)
print(res)
3.reduce
# reduce 传多个值 返回一个值
from functools import reduce
l1 = [11, 22, 33, 44, 55, 66, 77, 88]
res = reduce(lambda a, b: a * b, l1)
print(res)

重要内置函数

zip() 映射
zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象,这样做的好处是节约了不少的内存。
我们可以使用 list() 转换来输出列表。
如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。
l1=[11,22,33,44,55]
l2=['a','aa','aaa','aaaa','aaaaa']
l3=[1,2,3,4,5]
res=list(zip(l1,l2,l3))
print(res)
#[(11, 'a', 1), (22, 'aa', 2), (33, 'aaa', 3), (44, 'aaaa', 4), (55, 'aaaaa', 5)]
#如果对应关系缺少时会保留到当前数列
l1=[11,22,33,44,]
l2=['a','aa','aaa','aaaa','aaaaa']
l3=[1,2,3,]
res=list(zip(l1,l2,l3))
print(res)#类似于木桶效应
#[(11, 'a', 1), (22, 'aa', 2), (33, 'aaa', 3)]
filter() 过滤序列
函数用于过滤序列,过滤掉不符合条件的元素,返回一个迭代器对象,如果要转换为列表,可以使用 list() 来转换。
该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判断,然后返回 TrueFalse,最后将返回 True 的元素放到新列表中。
以下是 filter() 方法的语法:
filter(function, iterable)
l1=[11,22,33,44,55]
res=filter(lambda x:x>40,l1)
print(list(res))#[44, 55]
sorted 排序
sorted() 函数对所有可迭代的对象进行排序操作。
sort 与 sorted 区别:
sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。
list 的 sort 方法返回的是对已经存在的列表进行操作,而内建函数 sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作。
sorted(iterable, key=None, reverse=False) #reverse -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)
l1=[11,22,44,55,33]
res=sorted(l1)
print(list(res))

常见内置函数

abs() 绝对值
print(abs(-111))#111
all() 所有数据值对应的布尔值为True结果才是True 否则返回False
print(all([0,1,2,3]))#False
print(all([1,2,3]))#True
any()所有数据值对应的布尔值有一个为True结果就是True 否则返回False
print(any([0,None,'',1]))#True
print(any([0, None, '']))#False
bin() oct() hex() int()
bytes() 转换成bytes类型
s1='好好学习 天天向上'
print(s1.encode('utf8'))
print(bytes(s1,'utf8'))
callable()
callable() 函数用于检查一个对象是否是可调用的。如果返回 Trueobject 仍然可能调用失败;但如果返回 False,调用对象 object 绝对不会成功。
对于函数、方法、lambda 函式、 类以及实现了 __call__ 方法的类实例, 它都返回 True
name='jason'
def index():
print('from index')
print(callable(name))#False
print(callable(index))#True
chr() ord() 基于ASCII码做数字与字母转换
print(chr(65))#A
print(chr(90))#Z
print(chr(97))#a
print(chr(122))#z
dir()
dir() 函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。如果参数包含方法__dir__(),该方法将被调用。如果参数不包含__dir__(),该方法将最大限度地收集参数信息
dir 语法:
dir([object])
print(dir('hello'))
divmod()
python divmod() 函数把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a // b, a % b)。
res=divmod(100,2)
print(res)#(50,0)
res=divmod(13,2)
print(res)#(6,1)#适用于页码等
paga,more=divmod(999,2)
if more:
paga+=1
print('总页码',paga)#总页码 500
enumerate() 枚举
enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。
a=['aa','aa','aa','aa','aa','aa',]
a=enumerate(a)
print(list(a))#[(0, 'aa'), (1, 'aa'), (2, 'aa'), (3, 'aa'), (4, 'aa'), (5, 'aa')]
eval() exec()
eval() 函数用来执行一个字符串表达式,并返回表达式的值
以下是 eval() 方法的语法:
eval(expression[, globals[, locals]])
expression -- 表达式。
globals -- 变量作用域,全局命名空间,如果被提供,则必须是一个字典对象。
locals -- 变量作用域,局部命名空间,如果被提供,可以是任何映射对象。
s2 = 'for i in range(100):print(i)'
# eval(s2) # 只能识别简单的python代码 具有逻辑性的都不行
exec(s2) # 可以识别具有一定逻辑性的python代码
hash() 哈希加密
print(hash('123321'))#7770933146119379354 不同时间加密结果也不同
id() input() isinstance()
Python 中 id() 函数用于获取对象的内存地址。
isinstance()
isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()。
isinstance() 方法的语法:
isinstance(object, classinfo)
map() max() min()
open() #打开文件 with open()
pow()
pow() 方法返回 xy(x 的 y 次方) 的值。
print(pow(2,2))#4
print(pow(2,3))#8
print(pow(2,4))#16
range()
函数语法
range(start, stop[, step])
Python 3.x中不存在Python 2.x的xrange()。在Python 2.x中,range返回一个列表,即range3)返回[0,1,2],而xrange返回一个xrange对象,即xrange(3)返回iterator对象,它与Java迭代器类似,并在需要时生成数字。
如果我们需要多次迭代相同的序列,我们更喜欢range(),因为range提供了一个静态列表。xrange()每次重建序列。xrange()不支持切片和其他列表方法。xrange()的优点是,当任务迭代大范围时,它可以节省内存。
在Python 3.x中,范围函数现在执行xrange在Python 2.x中的功能,因此为了保持代码的可移植性,我们可能希望坚持使用范围。所以Python 3.x的范围函数是来自Python 2.x的xrange。
round()
round() 方法返回浮点数x的四舍五入值。
round( x [, n] )
x -- 数值表达式。
n -- 数值表达式,表示从小数点位数。
print "round(80.23456, 2) : ", round(80.23456, 2)#round(80.23456, 2) : 80.23
sum()
sum() 方法对序列进行求和计算。
print(sum([11,22,33,44,555,666]))#1331
zip()
zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。

可迭代对象

1可迭代对象
对象内置有__iter__方法的都称为可迭代对象
1.1内置方法 通过点的方式能够调用的方法
1.2__iter__ 双下iter方法
2可迭代对象的范围
不可迭代的对象
int float bool 函数对象
可迭代的对象
str list dict tuple set 文件对象
3可迭代的含义
更新换代(每次更新必须依赖上一次的结果)
手机更新
可迭代在python 中可以可以理解为是支持For循环

迭代器对象

1.迭代对象
是由可迭代对象调用__iter__方法产生的
迭代器对象判断的本质是看是否内置有__iter__和__next__
2.迭代器对象的作用
提供了一种不依赖于索引取值的方式
正因为有迭代器的存在 我们的字典 集合才能够被for循环
3.迭代器对象实操
s1 = 'hello' # 可迭代对象
res = s1.__iter__() # 迭代器对象
print(res.__next__()) # 迭代取值 for循环的本质
一旦__next__取不到值 会直接报错
4.注意事项
可迭代对象调用__iter__会成为迭代器对象 迭代器对象如果还调用__iter__不会有任何变化 还是迭代器对象本身

for循环内部原理

for 变量名 in 可迭代对象:
循环体代码
1.先将in后面的数据调用__iter__转变成迭代器对象
2.依次让迭代器对象调用__next__取值
3.一旦__next__取不到值报错 for循环会自动捕获并处理

异常处理

python提供了两个非常重要的功能来处理python程序在运行中出现的异常和错误。
异常就是代码运行报错 行业俗语叫bug
代码运行中一旦遇到异常会直接结束整个程序的运行 我们在编写代码的过程中药尽可能避免
2.异常分类
语法错误
不允许出现 一旦出现立刻改正 否则提桶跑路
逻辑错误
允许出现的 因为它一眼发现不了 代码运行之后才可能会出现
3.异常结构
错误位置
错误类型
错误详情
posted @   冰柠檬檬  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示