目录
- 文件
- 函数
- 装饰器
- 算法及二分法
- 三元表达式
- 各种生成式
- 名称空间
- 可迭代对象
- 迭代器对象
- for循环内部原理
- 异常处理
内容详解
文件
文件操作
- 文件的概念
- 就是操作系统暴漏给用户操作硬盘的快捷方式
- eg:双击一个文件,其实是从硬盘将数据加载到内存
- ctrl+s保存文件,其实是将内存中的数据刷到硬盘保存
- 代码打开文件的两种方式
- 方式一:
f = open(文件路径,读写模式,encoding='utf8') f.close() - 方式二:
with open('a.txt','r', encoding='utf8') as f1: with子代码块 ps:with上下文管理好处在于子代码运行结束自动调用close方法关闭资源
- 强调
open方法的第一个参数是文件路径 并且撬棍跟一些字母的组合会产生特殊的含义导致路径查找混乱 为了解决该问题可以在字符串的路径前面加字母r D:\a\n\t r'D:\a\n\t' 以后涉及到路径的编写 推荐加上r with支持一次性打开多个文件 with open() as f1,open() as f2,open() as f3: 子代码
文件读写模式
- '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'b.txt', 'w', encoding='utf8') as f: # pass # 2.文件路径存在:先清空文件内容 之后再写入 with open(r'a.txt', 'w', encoding='utf8') as f: f.write('假期综合征 赶紧要调整\n') f.write('假期综合征 赶紧要调整\n') f.write('假期综合征 赶紧要调整\n') 强调:换行符需要自己添加 并且在后续数据读取比对的时候也一定要注意它的存在 - 'a'只追加模式:文件末尾添加数据
# 1.文件路径不存在:自动创建 # with open(r'c.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
- 只能操作文本文件
- 读写都是以字符为单位
- 需要指定encoding参数,如果不知道则会采用计算机默认的编码
- 默认的模式,我们上面所写的r、w、a其实全称是rt、wt、at
- 'b'二进制模式(bytes模式)
- 不是默认的模式,需要自己指定rb、wt、at
- 可以操作任意类型的文件
- 读写都是以bytes为单位
不需要指定encoding参数,因为它已经是二进制模式,不需要编码
- 不是默认的模式,需要自己指定rb、wt、at
- 二进制模式与文本模式针对文件路径是否存在的情况下,规律是一样的!!!
文件诸多方法
- read()
- 一次性读取文件内容 并且光标停留在文件末尾 继续读取则没有内容
- 并且当文件内容比较多的时候 该方法还可能会造成计算机内存溢出
- 括号内还可以填写数字 在文本模式下 表示读取几个字符
- for循环
- 一行行读取文件内容 避免内存溢出现象的产生
- readline()
- 一次只读一行内容
- readlines()
- 一次性读取文件内容,会按照行数组织成列表的一个个数据值
- readable()
- 判断文件是否具备读数据的能力
- write()
- 写入数据
- writeable()
- 判断文件是否具备写数据的能力
- wrtelines()
- 接受一个列表,一次性将列表中所有的数据值写入
- flush()
- 将内存中文件数据立刻刷到硬盘,相当于ctrl+s功能
文件内光标的移动
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.read(2).decode('utf8'))
# f.seek(-1, 2)
# print(f.tell()) # 返回光标距离文件开头产生的字节数
"""
seek(offset, whence)
offset是位移量 以字节为单位
whence是模式 0 1 2
0是基于文件开头
文本和二进制模式都可以使用
1是基于当前位置
只有二进制模式可以使用
2是基于文件末尾
只有二进制模式可以使用
"""
# print(f.read(3).decode('utf8'))
文件内光标移动案例(了解)
import time
with open(r'a.txt', 'rb') as f:
f.seek(0, 2)
while True:
line = f.readline()
if len(line) == 0:
# 没有内容
time.sleep(0.5)
else:
print(line.decode('utf8'), end='')
计算机硬盘修改数据的原理(了解)
硬盘写数据可以看成是在硬盘上刻字 一旦需要修改中间内容 则需要重新刻字
因为刻过的字不可能从中间再分开
硬盘删除数据的原理
不是直接删除而是改变状态 等待后续数据的覆盖才会被真正删除
文件内容修改(了解)
# 修改文件内容的方式1:覆盖写
# with open(r'a.txt', 'r', encoding='utf8') as f:
# data = f.read()
# with open(r'a.txt', 'w', encoding='utf8') as f1:
# f1.write(data.replace('jason', 'tony'))
# 修改文件内容的方式2:换地写
'''先在另外一个地方写入内容 然后将源文件删除 将新文件命名成源文件'''
import os
with open('a.txt', 'r', encoding='utf8') as read_f, \
open('.a.txt.swap', 'w', encoding='utf-8') as write_f:
for line in read_f:
write_f.write(line.replace('tony', 'kevinSB'))
os.remove('a.txt') # 删除a.txt
os.rename('.a.txt.swap', 'a.txt') # 重命名文件
函数
函数前戏
name_list = ['jason', 'kevin', 'oscar', 'jerry']
# print(len(name_list))
'''突然len不准用了'''
# count = 0
# for i in name_list:
# count += 1
# print(count)
'''统计列表内数据值个数的代码需要在很多地方使用'''
# 相同的代码需要在不同的位置反复执行
"""
循环
相同的代码在相同的位置反复执行
函数
相同的代码在不同的位置反复执行
ps:相同的代码不是真正一模一样而是可以通过传入的数据不同而做出不同的改变
"""
def my_len():
count = 0
for i in name_list:
count += 1
print(count)
my_len()
"""
函数相当于是工具(具有一定功能)
不用函数
修理工需要修理器件要用锤子 原地打造 每次用完就扔掉 下次用继续原地打造
用函数
修理工提前准备好工具 什么时候想用就直接拿出来使用
"""
函数的语法结构
def 函数名(参数):
'''函数注释'''
函数体代码
return 返回值
1.def
定义函数的关键字
2.函数名
命名等同于变量名
3.参数
可有可无 主要是在使用函数的时候规定要不要外界传数据进来
4.函数注释
类似于工具说明书
5.函数体代码
是整个函数的核心 主要取决于程序员的编写
6.return
使用函数之后可以返回给使用者的数据 可有可无
函数的定义与调用
1.函数在定义阶段只检测语法 不执行代码
def func():
pass
2.函数在调用阶段才会执行函数体代码
func()
3.函数必须先定义后调用
4.函数定义使用关键字def函数调用使用>>>:函数名加括号
如果有参数则需要在括号内按照相应的规则传递参数(后续详细讲解)
函数的分类
1.空函数
函数体代码为空 使用的pass或者...补全的
空函数主要用于项目前期的功能框架搭建
def register():
"""注册功能"""
pass
2.无参函数
定义函数的时候括号内没有参数
def index():
print('from index function')
3.有参函数
定义函数的时候括号内写参数 调用函数的时候括号传参数
def func(a):
print(a)
函数的返回值
- 什么是返回值
- 调用函数之后返回给调用者的结果
- 如何获取返回值
- 变量名 赋值符号 函数的调用
- res = func() # 先执行func函数 然后将返回值赋值给变量res
- 函数返回值的多种情况
- 函数体代码中没有return关键字 默认返回None
- 函数体代码有return 如果后面没有写任何东西还是返回None
- 函数体代码有return 后面写什么就返回什么
- 函数体代码有return并且后面有多个数据值 则自动组织成元组返回
- 函数体代码遇到return会立刻结束
函数的参数
形式参数
在函数定义阶段括号内填写的参数 简称'形参'
实际参数
在函数调用阶段括号内填写的参数 简称'实参'
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""
形参与实参的关系
形参类似于变量名 在函数定义阶段可以随便写 最好见名知意
def register(name,pwd):
pass
实参类似于数据值 在函数调用阶段与形参临时绑定 函数运行结束立刻断开
register('jason',123) 形参name与jason绑定 形参pwd与123绑定
"""
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
函数参数之位置参数
"""
当子代码只有一行并且很简单的情况下,可以直接在冒号后编写不用换行
"""
# 函数位置形参和位置实参
# def funcl(a, b, c): pass # 位置形参 定义阶段括号内从左往右依次填写的变量名
# funcl(1, 2, 3) #位置实参 调用阶段括号内从左往右依次填写的数据值
def funcl(a, b):
print(a, b)
# funcl(1, 2) # 安装位置一一对应
# funcl(1) # 直接报错少一个也不行 同理多一个也不行
# funcl(b=1, a=2) # 关键字传参(指名道姓的传)
# funcl(b=1, 2) # 直接报错,关键字传参一定要跟在位置传参后面
# funcl(2, b=1) # ture
# funcl(1, b=1, a=2) # 报错,同一个形参调用的时候不能多次赋值
name = 'Gao'
pwd = '123'
# funcl(name, pwd) # 实参没有固定的定义 可以传数据值 也可以绑定数据值的变量名
# funcl(a=name, b=pwd) # 实参没有固定的定义 可以传数据值 也可以绑定数据值的变量名
"""
越短的越简单的越靠前
越长的越复杂的越靠后
但遇到一下情况例外
同一个形参在调用的时候不能多次赋值
"""
默认参数
-
默认参数可以简化函数的调用,降低调用函数的难度
-
设置默认参数时,有几点要注意:
- 必选参数在前,默认参数在后,否则Python的解释器会报错
- 如何设置默认参数
- 当函数有多个参数时,把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数
-
默认参数的定义也遵循短的简单的靠前 长的复杂的靠后
def student (name, age, gender='girl'):
print(f"""
----------学生信息----------
姓名:{name}
年龄:{age}
性别:{gender}
---------------------------
""")
student('gaoli', 23, 'boy')
student('dudu', 18)
student('jiajia', 19)
student('weiwei', 20)

可变长参数
- 可变长参数:指的是在调用函数时,传入的参数个数可以不固定
- 调用函数时,传值的方式无非两种,一种是位置实参,另一种是关键字实参,因此形参也必须得有两种解决方法,以此来分别接收溢出的位置实参(*)与关键字实参(**)
1.可变长形参之*
- 形参中的会将溢出的位置实参全部接收,然后存储元组的形式,然后把元组赋值给后的变量名-参数。需要注意的是:*后的变量名名约定俗成为args——参数。
def funcl(*a):
print(a)
funcl() # ()
funcl(1) # (1,)
funcl(1, 2, 3, 4) # (1, 2, 3, 4)
def func2(b, *a):
print(a, b)
func2() # 报错 函数至少需要一个参数给到b
func2(1) # () 1
func2(1, 2, 3, 4) # (2, 3, 4) 1
2.可变长形参之**
- 形参中的会将溢出的关键字实参全部接收,然后存储字典的形式,然后把字典赋值给后的参数——变量名。需要注意的是:**后的变量名约定俗成为kwargs——关键字参数。
def func3(**k):
print(k)
func3() # {}
func3(a=1) # {'a': 1}
func3(a=1, b=2, c=3) # {'a': 1, 'b': 2, 'c': 3}
def func4(a, **k):
print(a, k)
func4() # 报错 函数至少需要一个参数给到a
func4(a=1) # 1 {}
func4(a=1, b=2, c=3) # 1 {'b': 2, 'c': 3}
func4(a=1,b=2,c='Gaoli',d='jiajia') # 1 {'b': 2, 'c': 'Gaoli', 'd': 'jiajia'}
3.可变长形参之*与可变长形参之**混合使用
def func5(*a, **k):
print(a, k)
func5() # () {}
func5(1, 2, 3) # (1, 2, 3) {}
func5(a=1, b=2, c=3) # () {'a': 1, 'b': 2, 'c': 3}
func5(1, 2, 3, a=1, b=2, c=3) # (1, 2, 3) {'a': 1, 'b': 2, 'c': 3}
def func6(n, *a, **k):
print(n, a, k)
func6() # 函数至少需要一个参数给到n
func6(1, 2, 3) # 1 (2, 3) {}
func6(111, a=1, b=2, c=3) # 111 () {'a': 1, 'b': 2, 'c': 3}
func6(n=111, a=1, b=2, c=3) # 111 () {'a': 1, 'b': 2, 'c': 3}
func6(a=1, b=2, c=3, n=111) # 111 () {'a': 1, 'b': 2, 'c': 3}
func6(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
4.可变长实参之*
- 实参中的,会将后参数的值循环取出,打散成位置实参。以后但凡碰到实参中带的,它就是位置实参,应该马上打散成位置实参去看。(类似于for循环 将所有循环遍历出来的数据按照位置参数一次性传给函数)
def index(a, b, c):
print(a, b, c)
l1 = [123, 321, 132]
# 方法1索引取值(不推荐)
index(l1[0], l1[1], l1[2]) # 123 321 13
# 方法二用*来进行赋值
index(*l1) # 123 321 132
l2 = ['aaa', 'bbb', 'ccc']
index(*l2) # aaa bbb ccc
s1 = 'tom'
index(*s1) # t o m
set1 = {123, 1231, 321} # 集合不能重复否则会报错
index(*set1) # 321 123 1231
dic1 = {'username': 'Gaoli', 'pwd': 123, 'age': 23}
index(*dic1) # username pwd age取的是键
index(*dic1.values()) # Gaoli 123 23取的是值
5.可变长实参之**
- 实参中的,会将后参数的值循环取出,打散成关键字实参。以后但凡碰到实参中带的它就是关键字实参,应该马上打散成关键字实参去看(将字典打散成关键字参数的形式传递给函数)
def user_info(username, password, age):
print(name, password, age)
d1 = {'username': 'Gaoli', 'password': 123, 'age': 18}
user_info(username=d1['username'], password=d1['password'], age=d1['age']) # Gaoli 123 18
user_info(*d1.values()) # Gaoli 123 18
user_info(**d1) # Gaoli 123 18
user_info(username='Gaoli', password=123, age=18) # Gaoli 123 18
6.可变长实参*与可变长实参**使用
def index(*args, **kwargs):
print(args) # (11, 22, 33, 44)
print(kwargs) # {}
index(*[11, 22, 33, 44]) # index(11, 22, 33, 44)
index(*(11, 22, 33, 44)) # index(11, 22, 33, 44)
7.命名关键字形参(了解一下就好)
'''形参必须按照关键字参数传值>>>:命名关键字参数'''
def index(name, *args, gender='male', **kwargs):
print(name, args, gender, kwargs)
index('jason',1,2,3,4,a=1,b=2)
index('jason', 1, 2, 3, 4, 'female', b=2)
global与nonlocal
money = 666
def index():
global money # 局部修改不可变全局名称money数据值(global)
money = 123
index() # 调用
print(money) # 123
'''
局部名称空间直接修改全局名称空间中的数据
'''
def index():
name = 'gaoli'
def inner():
nonlocal name # 局部名称内层修改外层局部名称空间中的数据值
name = 'kevin'
inner()
print(name)
index() # 调用 kevin
'''
内层局部名称空间修改外层局部名称空间中的数据
'''
函数名的多种用法
函数名其实绑定的也是一块内存地址,只不过该地址里面存放的不是数据值而是一段代码,函数名加()就会找到该代码并执行。
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()
def index():
print('from index')
def func():
print('from func')
return func
res = index()
print(res)
res()
4.可以当做容器类型(可以存放多个数据的数据类型)的数据
def register():
print('注册功能')
def login():
print('登录功能')
def withdraw():
print('提现功能')
def transfer():
print('转账功能')
def shopping():
print('购物功能')
func_dict ={
'1': register,
'2': login,
'3': withdraw,
'4': transfer,
'5': shopping
}
while True:
print("""
1.注册功能
2.登录功能
3.提现功能
4.转账功能
5.购物功能
""")
choice = input('请输入功能编号>>>:').strip() # 获取一个用户所执行的编号
if choice in func_dict: # 如果用户输入功能字典的编号
func_name = func_dict.get(choice) # 定义一个值所绑定的内存地址
func_name() # 调用
else:
print('功能编号不存在')
5.以前写法
while True:
print("""
1.注册功能
2.登录功能
3.提现功能
4.转账功能
5.购物功能
""")
choice = input('请输入功能编号>>>:').strip()
if choice == '1':
register()
elif choice == '2':
login()
elif choice == '3':
withdraw()
elif choice == '4':
transfer()
elif choice == '5':
shopping()
else:
print('可算写完了')
闭包函数
"""
定义在函数内部的函数 并且用到了外部函数名称空间中的名字
1.定义在函数内容
2.用到外部函数名称空间中的名字
"""
def index():
name = 'gaoli'
def inner():
print(name)
闭包函数实际应用>>>:是另外一种给函数体代码传参的方式!!!
- 给函数体代码传参的方式1:代码里面缺什么变量名形参里面就补什么变量名
def register(name,age):
print(f"""
姓名:{name}
年龄:{age}
""")
register('jason', 18)
- 给函数体代码传参的方式2:闭包函数
def outer(name, age):
# name = 'jason'
# age = 18
def register():
print(f"""
姓名:{name}
年龄:{age}
""")
return register
res = outer('jason', 18)
res()
res()
res = outer('kevin', 28)
res()
res()
res()
递归函数
- 函数的递归调用
- 函数直接或者间接的调用了函数自身
# 直接调用
def index()
print('from index')
index()
index()
# 间接
def index():
print('from index')
func()
def func():
print('from func')
index()
func()
'''最大递归深度:python解释器添加的安全措施''
coun = 0
def index():
global count
count +=1
print(count)
index()
index()
'''官网提供最大递归深度为1000 我们在测试的时候可能会出现996、997、998'''
- 递归函数
- 直接或者间接调用自己
- 每次调用都必须比上一次简单,并且需要有一个明确的结束条件。
- 递推:一层层往下
- 回溯:基于明确的结果一层层往上
"""
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)
匿名函数
- 没有名字的函数——需要使用管卷子lambda
- 语法结构
- lambda 形参:返回值
- 使用场景
- lambda a, b:a+b
- 匿名函数一般不单独使用——需要配合其他函数一起用
常见内置函数
- map() 映射
l1 = [1, 2, 3, 4, 5]
# def func(a):
# return a + 1
res = map(lambda x: x + 1, l1)
print(list(res))
- max()\min()
l1 = [11, 22, 33, 44]
res = max(l1)
d1 = {
'zj': 100,
'jason': 8888,
'berk': 99999999,
'oscar': 1
}
res = max(d1, key=lambda k: d1.get(k))
print(res)
def func(a):
return d1.get(a)
res = max(d1, key=func)
print(res)
- reduce 传多个值 返回一个值
from functools import reduce
l1 = [1, 2, 3, 4, 5, 6, 7, 8]
res = reduce(lambda a, b: a + b, l1)
print(res)
* zip 函数是可以接收多个可迭代对象,然后把每个可迭代对象中的第i个元素组合在一起,形成一个新的迭代器,类型为元组。
```python
l1 = [11, 22, 33, 44]
l2 = ['jason', 'kevin', 'oscar', 'jerry']
l3 = [1, 2, 3, 4]
res = zip(l1, l2, l3)
print(list(res)) # [(11, 'jason', 1), (22, 'kevin', 2), (33, 'oscar', 3), (44, 'jerry', 4)]
- zip 三个列表的长度不等,则zip所返回的迭代器的长度将有长度最短的那个列表决定。
l1 = [11, 22, 33]
l2 = ['jason', 'kevin', 'oscar', 'jerry', 'tony']
l3 = [1, 2, 3, 4]
res = zip(l1, l2, l3)
print(list(res)) # [(11, 'jason', 1), (22, 'kevin', 2), (33, 'oscar', 3)]
- filter 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。
l1 = [11, 22, 33, 44, 55, 66, 77, 88, 99]
res = filter(lambda x: x < 40, l1)
print(list(res)) # [11, 22, 33]
- sorted 排序函数 默认升序
l1 = [12, 21, 18, 17, 22, 33, 20, 5]
res = sorted(l1)
print(res) # [5, 12, 17, 18, 20, 21, 22, 33]
常见内置函数
# 1.abs() 绝对值
print(abs(-100))
print(abs(100))
# 2.all() 所有数据值对应的布尔值为True结果才是True 否则返回False
print(all([0, 1, 2, 3]))
print(all([1, 2, 3, True]))
# 3.any() 所有数据值对应的布尔值有一个为True结果就是True 否则返回False
print(any([0, None, '', 1]))
print(any([0, None, '']))
4.bin() oct() hex() int()
# 5.bytes() 转换成bytes类型
s1 = '今天周五 内容也很简单'
print(s1.encode('utf8'))
print(bytes(s1, 'utf8'))
# 6.callable() 判断名字是否可以加括号调用
name = 'jason'
def index():
print('from index')
print(callable(name)) # False
print(callable(index)) # True
# 7.chr() ord() 基于ASCII码表做数字与字母的转换
print(chr(65)) # A
print(ord('A')) # 65
# 8.dir() 返回括号内对象能够调用的名字
print(dir('hello'))
# 9.divmod() 元组 第一个数据为整除数 第二个是余数
res = divmod(100, 2)
print(res) # (50, 0)
res = divmod(100, 3)
print(res)
"""
总数据 每页展示的数据 总页码
100 10 10
99 10 10
101 10 11
"""
page_num, more = divmod(9999, 20)
print(divmod(99, 10)) # (9, 9)
if more:
page_num += 1
print('总页码为:', page_num) # 总页码为: 500
10.enumerate() 枚举
# 11.eval() exec() 能够识别字符串中的python并执行
s1 = 'print("哈哈哈")'
eval(s1)
exec(s1)
s2 = 'for i in range(100):print(i)'
eval(s2) # 只能识别简单的python代码 具有逻辑性的都不行
exec(s2) # 可以识别具有一定逻辑性的python代码
# 12.hash() 哈希加密
print(hash('jason'))
13.id() input() isinstance()
14.map() max() min()
15.open()
# 16.pow() 幂指数(次方)
print(pow(2, 2))
print(pow(2, 3))
print(pow(2, 4))
17.range()
# 18.round() 四舍五入
print(round(98.3))
print(round(98.6))
# 19.sum()
print(sum([11, 22, 33, 44, 55, 66]))
20.zip()
装饰器
装饰器简介
-
概念
在不改变被装饰对象原代码和调用方式的情况下给被装饰对象添加新的功能 -
本质
并不是一门新的技术 而是由函数参数、名称空间、函数名多种用法、闭包函数组合到一起的结果 -
口诀
对修改封闭 对扩展开放 -
储备知识
'时间相关操作'
import time
print(time.time()) # 时间戳(距离1970-01-01 00:00:00所经历的秒数)
time.sleep(3)
print('睡醒了 干饭')
count = 0
# 循环之前先获取时间戳
start_time = time.time()
while count < 100:
print('哈哈哈')
count += 1
end_time = time.time()
print('循环消耗的时间:', end_time - start_time)
装饰器推导流程
import time
def index():
time.sleep(3)
print('from index')
def home():
time.sleep(1)
print('from home')
'''1.直接在调用index函数的前后添加代码'''
# start_time = time.time()
# index()
# end_time = time.time()
# print('函数index的执行时间为>>>:', end_time-start_time)
'''2.index调用的地方较多 代码不可能反复拷贝>>>:相同的代码需要在不同的位置反复执行>>>:函数'''
# def get_time():
# start_time = time.time()
# index()
# end_time = time.time()
# print('函数index的执行时间为>>>:', end_time - start_time)
# get_time()
'''3.函数体代码写死了 只能统计index的执行时间 如何才能做到统计更多的函数运行时间 直接传参变换统计的函数'''
# 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.虽然实现了一定的兼容性 但是并不符合装饰器的特征 第一种传参不写 只能考虑闭包'''
# 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.调用方式还是不对 如何变形>>>:变量名赋值绑定 (******)'''
# 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.上述装饰器只能装饰无参函数 兼容性太差'''
# 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.被装饰的函数不知道有没有参数以及有几个参数 如何兼容'''
# 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.如果被装饰的函数有返回值'''
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)
func1 = outer(func1)
res = func1(123, 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(fun2):
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
@outter2
@outter3
def index():
print('from index')
'''
多层语法糖,加载顺序由下而上。
每次执行之后如果上面还有语法糖,则直接将返回值函数名传给上面的语法糖。
如果上面没有语法糖了,则变形 index = outter(wrapper2)
'''
有参装饰器
# 效验用户是否登录装饰器
def outter(mode):
def login_auth(func_name):
def inner(**args, **kwargs):
username = input('username>>>:').strip()
password = input('password>>>:').strip()
if mode =='1':
print('数据直接写死')
elif mode =='2':
print('数据来源于文本文件')
elif mode ='3':
print('数据来源于字典')
elif mode =='4':
print('数据来源于MySQL')
return inner
return login_auth
'''当装饰器中需要额外的参数时>>>:有参装饰器'''
'''
函数名加括号执行优先级最高,有参装饰器情况
先看函数名加括号的执行
然后再是语法糖的操作
'''
# @outter('1')
def index():
print('from index')
index()
# @outter('2')
def func()
print('from func')
func()
装饰器模板
# 最常用的无参装饰器
def outer(func_name):
def inner(*args, **kwargs):
res = func_name(*args, **kwargs)
return res
return inner
@outer
def index():
pass
# 不常用的有参装饰器
def outter_plus(mode):
def outer(func_name):
def inner(*args, **kwargs):
rse = func_name(*args, **kwargs)
return res
return inner
return outer
@outer_plus('MySQL')
def func():
pass
装饰器修复技术
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
deffunc():
'''我是真正的func 我很强大 我很厉害 我很聪明'''
pass
help(func)
print(func)
func()
算法及二分法
算法简介及二分法
- 什么是算法
1.1 算法就是解决问题的有效方法,不是所有的算法都很高效也与不合格的算法 - 算法应用场景
2.1 推荐算法(抖音视频推送、淘宝商品推送)
2.2 成像算法(AI相关).....
2.3 几乎涵盖了我们日常生活中的方方面面 - 算法工程师要求
3.1 待遇非常好,但是要求也非常高 - 算法部门
4.1 不是所有的互联网公司养的起算法部分、只有大型互联网公司才有
4.2 算法部门类似于研发部分 - 二分法
5.1 是算法中最简单的算法,甚至都称不上是算法
5.2 使用要求:待查找的数据集必须有序
5.3 缺陷:针对开头结尾的数据 查找效率很低
5.4 常见算法的原理以及伪代码:二分法、冒泡、开拍、插入、堆排、桶排、数据结构(链表、约瑟夫问题、如何链表是否成环)
l1 = [12, 21, 32, 43, 56, 76, 87, 98, 123, 321, 453, 565, 678, 754, 812, 987, 1001, 1232]
# 查找列表中某个数据值
# 方式一:for循环,循环次数太多了。
# 方式2:二分法,不断的对数据集做二分切割。
'''代码实现二分法'''
# 定义我们想要查找的数据值
# target_num = 987 没必要 直接最后取值
def get_middle(l1, target_num):
if len(l1) == 0:
print('抱歉没有找到')
return
# 1.获取列表中间索引值
middle_index = len(l1)//2
# 2.比较目标数据值与中间值索引的大小
if target_num > l1[middle_index]:
# 3.切片保留右边一半
right_l1 = l1[middle_index+1:]
print(right_l1)
# 4.针对右边一半的列表继续二分并判断》》》:感觉要用递归函数
return get_middle(right_l1, target_num)
elif target_num < l1[middle_index]:
# 5.切片保留列表左边一半
left_l1 = l1[:middle_index]
print(left_l1)
# 针对左边一半的列表继续二分并判断 >>>: 感觉要用递归函数
return get_middle(left_l1, target_num)
else:
print('找到了')
get_middle(l1, 987)
# [453, 565, 678, 754, 812, 987, 1001, 1232]
# [987, 1001, 1232]
# [987]
get_middle(l1, 2000)
# [453, 565, 678, 754, 812, 987, 1001, 1232]
# [987, 1001, 1232]
# [1232]
# []
get_middle(l1, 12)
# [12, 21, 32, 43, 56, 76, 87, 98, 123]
# [12, 21, 32, 43]
# [12, 21]
# [12]
# 找到了
# target:目标 middle:中间 len:长度 get:获得 index:索引
三元表达式
三元素表达式
-
数据值1 if 条件 else 数据值2
-
条件成立则使用数据值1 条件不成立则使用数据值2
-
当结果是二选一的情况下 使用三元表达式较为简便
-
并且不推荐多个三元表达式嵌套
# 简化步骤1:代码简单并且只有一行-那么可以直接在冒号后面编写
name = 'MrZhang'
if name =='MrZhang':print('老师')
else:print('学生')
# 三元表达式
res = '老师' if name =='MrZhang'else'学生'
print(res)
各种生成式
各种生成式/表达式/推导式
- 列表生成式
- 列表 = [被追加的数据 循环语句 循环或判断语句]
numbers_list = [1, 2, 3, 4, 5, ]
# 给列表中所有数据后面加.txt的后缀
# for循环
new_list = []
for number in numbers_list:
data = f'{number}.txt'
new_list.append(data)
print(new_list)
''' data:数据、资料 append:附加、追加 '''
# 列表生成式
# 先看for循环、每次for循环之后再看for关键字前面的操作
number1_list = ['1', '2', '3', '4', '5']
new_list = [number + '.txt' for number in number1_list]
print(new_list)
new_list = ['老大' if number == '1' else '小老弟' for number in number1_list if number != '5']
print(new_list)
- 字典生成式
- 字典 = {键数据:值数据 循环语句 循环或判断语句
s1 = 'hello world'
for i, j in enumerate(s1, start=100): # enumerate:列举 start:开始 i, j = k:v(键:值)
print(i, j)
# 100 h
# 101 e
# 102 l
# 103 l
# 104 o
# 105
# 106 w
# 107 o
# 108 r
# 109 l
# 110 d
d1 = {i: j for i, j in enumerate('hello world')}
print(d1)
# {0: 'h', 1: 'e', 2: 'l', 3: 'l', 4: 'o', 5: ' ', 6: 'w', 7: 'o', 8: 'r', 9: 'l', 10: 'd'}
- 集合生成式
- 集合 =
res = {i for i in 'hello'}
print(res)
# {'l', 'o', 'h', 'e'}
- 元组生成>>>:没有元组生成式,它是生成器.
res = (i+'sb' for i in 'hello')
print(res)
# <generator object <genexpr> at 0x000001F4DE2C1D58> :生成器
for i in res:
print(i)
# hsb
# esb
# lsb
# lsb
# osb
名称空间
名称空间
name = 'Gaoli'
1.申请内存空间存储Gaoli
2.给Gaoli绑定一个变量名name
3.后续通过变量名name就可以访问到Gaoli
名称空间即存放名字与对象映射/绑定关系的地方。对于y=6,Python会申请内存空间存放对象6,然后将名字y与6的绑定关系存放于名称空间中,del x表示清除该绑定关系。
在程序执行期间最多会存在三种名称空间
- 内置名称空间
- 解释器运行自动产生 里面包含了很多名字
- eg:len print input
- 解释器运行自动产生 里面包含了很多名字
- 全局名称空间
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文件级别的全局有效
- 局部名称空间
- 函数体代码内有效
名字的查找顺序
- 涉及到名字的查找 一定要先搞明白自己在哪个空间
- 当我们在局部名称空间中的时候
- 局部名称空间 >>> 全局名称空间 >>> 内置名称空间
- 当我们在全局名称空间中的时候
- 全局名称空间 >>> 内置名称空间
- 当我们在局部名称空间中的时候
- 其实名字的查找顺序是可以打破的
查找顺序案例
- 相互独立的局部名称空间默认不能够互相访问
def func1():
name = 'jason'
print(age)
def func2():
age = 18
print(name)
- 局部名称空间嵌套
- 先从自己的局部名称空间查找 之后由内而外依次查找
x = '123321' # D1
def func1(): # D3
x = 1
def func2(): # D5
x = 2
def func3(): # D7
x = 3
print(x)#3
func3() # D6
print(x)#2
func2() # D4
print(x)#1
func1() # D2
print(x)#123321
可迭代对象
- 可迭代对象
- 对象内置有_iter_方法的都称为可迭代对象
- 内置方法:通过点的方式能够调用的方法
- iter:双下iter方法
- 可迭代对象的范围
- 不是可迭代对象
- int、float、bool、函数对象
- 是可迭代对象
- str、list、dict、tuple、set、文件对象
- 不是可迭代对象
- 可迭代的含义
- 迭代:更新换代(每次更新都必须依赖上一次的结果)
- eg:手机app更新
- 可迭代在python中可以理解为是否支持for循环
- 迭代:更新换代(每次更新都必须依赖上一次的结果)
迭代器对象
- 迭代器对象
- 是由可迭代对象调用_iter_方法产生的
- 迭代器对象判断的本质是看是否内置有_iter_和_next_
- 迭代器对象的作用
- 提供了一种不依赖索引取值的方式
正因为有迭代器的存在,我们的字典,集合才能够被for循环
- 提供了一种不依赖索引取值的方式
- 迭代器对象实操
s1 = 'hello' # 可迭代对象
res = s1._iter_() # 迭代器对象
print(res._next_()) # 迭代取值、for循环本质
一旦_next_取不到值,就会直接报错
- 注意事项
- 可迭代对象调用_iter_会成为迭代器对象、迭代器对象如果还调用_iter_不会有任何变化、还是迭代器对象本身
for循环内部原理
- for 变量名 in 可迭代对象:
- 循环体代码
- 先将in后面的数据值调用_iter_转变成迭代器对象
- 依次让迭代器对象调用_next_取值
- 一旦_next_取不到值报错。for循环会自动捕获并处理
异常处理
- 异常
- 异常就是代码运行报错、行业俗语叫bug
- 代码运行中一旦遇到异常会直接结束整个程序的的运行、我们在编写代码的过程中药可能避免。
- 异常分类
- 语法错误
- 不允许出现、一旦出现立刻改正、否则体桶跑路
- 逻辑错误
- 允许出现的、因为它一眼发现不了、代码运行之后才可能会出现
- 语法错误
- 异常结构
- 错误位置
- 错误类型
- 错误详情
浙公网安备 33010602011771号