递归函数
"""
递归:函数在运行过程中 直接或者间接的调用了自身
"""
# 官网表示:python默认的最大递归深度为1000次(根据CPU不同一般在997-1000次。)
import sys
print(sys.getrecursionlimit()) # 查看默认递归深度
# print(sys.setrecursionlimit(2000)) #手工设置递归调用深度,2000可以换成任意数。
count = 1
def index():
global count
count += 1
print(count)
print('from index')
index()
index()
# def func():
# print('from func')
# index()
# def index():
# print('from index')
# func()
# index()
"""
递归
1.递推
一层层往下推导答案(每次递归之后复制度相较于上一次一定要有所下降)
2.回溯
依据最后的结论往后推导出最初需要的答案
递归一定要有结束条件!!!
"""
# 伪代码:可能无法运行 但是可以表述逻辑
# age(5) = age(4) + 2
# age(4) = age(3) + 2
# age(3) = age(2) + 2
# age(2) = age(1) + 2
# age(1) = 18
# def get_age(n):
# if n == 1:
# return 18
# return get_age(n - 1) + 2
# print(get_age(5))
l = [1,[2,[3,[4,[5,[6,[7,[8,[9,[10,[11,[12,[13,[14,]]]]]]]]]]]]]]
# 打印出列表中每一个元素(列表除外)
# 1.循环该列表 获取列表内每一个元素
# 2.判断该元素是否是数字 如果是数字 则直接打印
# 3.如果是列表 则循环该列表 获取列表内每一个元素
# 4.判断该元素是否是数字 如果是数字 则直接打印
# 5.如果是列表 则循环该列表 获取列表内每一个元素
# 6.判断该元素是否是数字 如果是数字 则直接打印
# 7.如果是列表 则循环该列表 获取列表内每一个元素
def get_num(l):
for i in l:
if type(i) is int:
print(i)
else:
# 也是for循环 然后判断
get_num(i)
get_num(l)
# for i in []:
# print(i,'懵逼了!')
算法之二分法
# 什么是算法?
解决问题的高效方法
# 二分法(入门级别:还有一定距离)
l = [11, 23, 43, 57, 68, 76, 81, 99, 123, 321, 432, 567, 666, 712, 899, 999, 1111]
# 第一种方式 直接for循环从左往右依次查找
# 第二种方式 二分法
"""
二分法能够使用的场景 数据集必须有序
"""
def my_partner(target_num, list1): # 设置一个函数my_partner.里面2个形参,target_num和列表list1
if len(list1) == 0: # 如果列表长度索引为0,即没有元素,提示用户没有这个数。返回给用户说没有这个数。·
print('没有这个数')
return
middle_index = len(list1) // 2 # 分两半 结果是每一半为8
if target_num > list1[middle_index]: # 判断中间索引对应的值比目标值大还是比目标值小。
list1_right = list1[middle_index + 1:] # 获取列表list1 索引9以后的所有元素
print(list1_right) # 验证一下是否获取到了列表list1右边的那一段元素
my_partner(target_num, list1_right) # 返回函数初始再次运行,即:重新判断重新切片列表
elif target_num < list1[middle_index]: # 如果要找的数字比列表中间索引对应的值小,那么往左边找
list1_left = list1[:middle_index] # 把列表左边切片下来
print(list1_left) # 打印验证一下列表
my_partner(target_num, list1_left) # 返回函数初始再次运行,即:重新判断重新切片列表
else: # 其他情况(即要找的数字不符合上面条件,等于找到的数字)就提示用户找到了
print('提示用户找到了')
# my_partner(444, l) 找不到 需要添加结束条件
# my_partner(11, l) # 要查找的元素在开头 那么还没有依次查找的效率高
三元表达式
# def my_max(a, b):
# if a > b:
# return a
# else:
# return b
"""
当功能需求仅仅是二选一的情况下 那么推荐使用三元表达式
"""
# def my_max(a, b):
# return a if a > b else b
"""
条件成立采用if前面的值 if 条件 else 条件不成立采用else后面的值
三元表达式尽量不要嵌套使用
"""
# res = '干饭' if 10 > 2 else '不干饭'
# print(res)
# res = '干饭' if 10 > 2 else ('不管饭' if 2 >5 else '写的啥!')
# print(res)
# is_free = input('电影是否收费(y/n)>>>:').strip()
# if is_free == 'y':
# print('收费')
# else:
# print('免费')
# print('收费' if is_free == 'y' else '免费')
username = input('username>>>:')
res = 'NB' if username == 'jason' else 'SB'
print(res)
列表生成式
name_list = ['jason', 'kevin', 'tony', 'jerry']
# 给列表中所有的人名加上_DSB后缀
'''传统做法'''
# 1.定义一个空列表
# new_list = []
# 2.for循环老列表
# for name in name_list:
# 3.生成新的名字
# new_name = '%s_DSB'%name
# 4.添加到新的列表中
# new_list.append(new_name)
# print(new_list)
'''列表生成式'''
# res = ['%s_DSB' % name for name in name_list]
# print(res)
'''传统做法'''
# 1.定义一个空列表
# new_list = []
# # 2.for循环老列表
# for name in name_list:
# # 3.生成新的名字
# if name == 'jason':
# continue
# else:
# new_name = '%s_DSB'%name
# # 4.添加到新的列表中
# new_list.append(new_name)
# print(new_list)
'''列表生成式'''
# res = ['%s_DSB' % name for name in name_list if name != 'jason']
# print(res)
字典生成式

# l1 = ['name', 'age', 'hobby']
# l2 = ['jason', 18, 'read']
# new_dict = {}
# for i in range(len(l1)):
# new_dict[l1[i]] = l2[i]
# print(new_dict)
# count = 0
# for i in l1:
# print(count,i)
# count += 1
# 枚举
'''
enumerate(l1)
针对该方法使用for循环取值 每次会产生两个结果
第一个是从0开始的数字
第二个是被循环对象里面的元素
还可以通过start参数控制起始位置
'''
# for i, j in enumerate(l1, start=1):
# print(i, j)
name_list = ['jason', 'kevin', 'tony', 'jerry']
# res = {i: j for i, j in enumerate(name_list) if j != 'jason'}
# print(res)
# res1 = {i for i,j in enumerate(name_list)}
# print(res1,type(res1))
# 迭代器
res2 = (i for i,j in enumerate(name_list))
print(res2)
匿名函数
# 匿名函数:没有名字的函数
"""
语法格式
lambda 形参:返回值
"""
# print(lambda x:x**2)
# def index():
# pass
# print(index)
# print((lambda x: x ** 2)(2))
# res = lambda x: x ** 2
# print(res(2))
'''匿名函数一般不会单独使用 都是配合其他函数一起使用'''
# map() 映射
# l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# def index(n):
# return n ** 2
# print(list(map(lambda x:x**2, l)))
常用内置函数
# 1.map() 映射
l = [1,2,3,4]
map(lambda x:x+1,l) # 循环获取列表中每个元素并传递给匿名函数保存返回值
# 2.zip() 拉链
l = [11, 22, 33, 44, 55, 66, 77]
name_list = ['jason', 'kevin', 'tony', 'jerry']
l1 = [1, 2, 3, 4, 5, 6, 7]
l2 = [8, 7, 6, 4, 3, 2, 1]
# new_list = []
# for i in range(len(l)):
# new_list.append((l[i],name_list[i]))
# print(new_list)
new_list = zip(l, name_list, l1, l2)
print(list(new_list))
# 返回结果:[(11, 'jason', 1, 8), (22, 'kevin', 2, 7), (33, 'tony', 3, 6), (44, 'jerry', 4, 4)]
# 把多个列表的元素拼接在新列表,拼接次数按照最少的索引列表(即name_list 4个元素拼接4次),多余的元素直接舍弃。
# 3.max与min max求最大值 min求最小值
# 列表:
# l = [11, 22, 33, 44, 55, 66, 77]
# print(max(l))
# print(min(l))
# 字典
# 字典不能直接max求最大值print(max(d)),而是应该套用函数。
# 现在我们有这样一个字典:
d = {
'jason':3000,
'Bevin':1000000,
'Ascar':10000000000,
'aerry':88888
}
def index(key):
return d[key]
print(max(d,key=lambda key:d[key])) # for循环先取值 之后再比较大小
"""
直接比max比大小是比key的大小。
Key属于字符串类型,按照ASCII码表
A-Z 65-90
a-z 97-122
"""
# 最小值
print(min(d,key=lambda key:d[key])) # jason
# 4.filter 过滤
l = [11, 22, 33, 44, 55]
res = filter(lambda x: x > 30, l)# 过滤掉30以下的元素
print(list(res)) # [33, 44, 55]
# 5.reduce 归总
from functools import reduce
d = [11, 22, 33, 44, 55, 66, 77, 88, 99]
res = reduce(lambda x, y: x + y, d)# 把全部元素加起来得到的数,返回结果是495
res1 = reduce(lambda x, y: x + y, d, 100) # 还可以额外添加元素值.返回结果是595
print(res)
可迭代对象
# 迭代
迭代即更新换代 每次的更新都必须依赖于上一次的结果
'''迭代其实给我们提供了一种不依赖索引取值的方式'''
# 可迭代对象
内置有__iter__方法的都称之为可迭代对象
内置的意思是可以通过点的方式直接查看到的
"""
针对双下滑线开头 双下滑线结尾的方法 最为专业标准的读法为
双下方法名
面向对象的时候为了与隐藏变量区分开
"""
# 以下属于迭代,每次的更新都必须依赖于上一次的结果
# n = 1
# while True:
# n+=1
# print(n)
# l = [11,22,33,44,55,66]
# n = 0
# while n < len(l):
# print(l[n])
# n += 1
# __iter__ 双下iter的内置方法
i = 12 # 整型没有
f = 11.11 # 浮点型没有
s = 'jason' # 字符串有
l = [111,22,33,4] # 列表有
d = {'username':'jason','pwd':123} # 字典有
t = (11,22,33) # 元祖有
se = {11,22,33} # 集合有
b = True # 布尔值没有
# file = open(r'a.txt','w',encoding='utf8')# 文件对象有
"""
含有__iter__的有
字符串 列表 字典 元组 集合 文件对象
上述通常为可迭代对象
"""
print(d)
print(d.__iter__()) # 等价于调用了一个内置方法 d.get()
print(iter(d))
print(d.__len__())
print(len(d))
"""
可迭代对象调用__iter__方法会变成迭代器对象(老母猪)
__iter__方法在调用的时候还有一个简便的写法iter()
一般情况下所有的双下方法都会有一个与之对应的简化版本 方法名()
例如__len__可以简便写成len() 用来统计长度
"""
迭代器对象
"""
迭代器对象
即含有__iter__方法 又含有__next__方法
如何生成迭代器对象
让可迭代对象执行__iter__方法
文件对象本身即是可迭代对象又是迭代器对象
迭代器对象无论执行多少次__iter__方法 还是迭代器对象(本身)
迭代器给我们提供了不依赖于索引取值的方式
"""
# 迭代器对象
i = 12 # 没有
f = 11.11 # 没有
s = 'jason' # 有
l = [111,222,333,444] # 有
d = {'username':'jason','pwd':123} # 有
t = (11,22,33) # 有
se = {11,22,33} # 有
b = True # 没有
file = open(r'a.txt','w',encoding='utf8') # 有
# res = s.__iter__() # 转成迭代器对象
# print(res.__next__()) # 迭代器对象执行__next__方法其实就是在迭代取值(for循环)
# print(res.__next__())
# print(res.__next__())
# print(res.__next__())
# print(res.__next__())
# res = d.__iter__() # 转成迭代器对象
# print(res.__next__()) # 迭代器对象执行__next__方法其实就是在迭代取值(for循环)
# print(res.__next__())
# print(res.__next__()) # 取完元素之后再取会"报错"
# 易错
# print(d.__iter__().__next__()) # username
# print(d.__iter__().__next__()) # username
# print(d.__iter__().__next__()) # username
# print(d.__iter__().__next__()) # username
# print(d.__iter__().__next__()) # username
# print(d.__iter__().__next__()) # username
# 每次都是取第一个元素,并没有迭代去取下一个元素,所以不会报错
for循环的本质
l1 = [1,2,3,4,5,6,7,8,9,11,22,33,44,55]
# 循环打印出列表中每个元素 但是不能使用for循环 __next__() next()
# 1.先将列表转为迭代器对象
# res = l1.__iter__()
# # 2.循环执行__next__取值
# while True:
# print(res.__next__())
# for i in l1:
# print(i)
"""
for循环内部原理
1.将关键字in后面的数据先调用__iter__方法转为迭代器对象
2.循环执行__next__方法
3.取完之后__next__会报错 但是for循环会自动捕获该错误并处理
res = 数据.__iter__()
while True:
检测代码是否会报错
res.__next__()
如果报错了则自动处理掉并结束while循环
"""
### for循环本质
```python
d = {'name':'jason','pwd':123,'hobby':'read'}
res = d.__iter__() # StopIteration
while True:
try:
print(res.__next__())
except StopIteration as e:
break
for i in d:
print(i)
迭代取值与索引取值对比
"""
迭代取值
优点:
1.不依赖于索引的一种通用取值方式
缺点:
1.取值的顺序永远都是固定的从左往右 无法重复获取
索引取值
缺点:
1.需要提供有序容器类型才可取值(不是一种通用的方式)
优点:
1.可以重复取值
"""
异常捕获
### 异常捕获
```python
# 什么是异常
代码运行出错会导致异常 异常发生后如果没有解决方案则会到底整个程序结束
# 异常三个重要组成部分
1.traceback
翻到最下面从下往上的第一个蓝色字体鼠标左键点击即可跳转到错误的代码所在的行
2.XXXError
错误的类型
3.错误类型冒号后面的内容
错误的详细原因(很重要 仔细看完之后可能就会找到解决的方法)
# 错误的种类
1.语法错误
不被允许的 出现了应该立刻修改!!!
2.逻辑错误
可以被允许的 出现了之后尽快修改即可
'''修改逻辑错误的过程其实就是在从头到尾理清思路的过程'''
# print(idna) # NameError
# l = [11,22,33]
# print(l[100]) # IndexError
# d = {'username':'jason'}
# print(d['xxx']) # KeyError
# int('abc') # ValueError
"""
基本语法结构
try:
有可能会出错的代码
except 错误类型 as e:
出错之后对应的处理机制(e是错误的详细信息)
except 错误类型 as e:
出错之后对应的处理机制(e是错误的详细信息)
except 错误类型 as e:
出错之后对应的处理机制(e是错误的详细信息)
# try:
# int('abc')
# except NameError as e:
# print('变量名name不存在',e)
# except ValueError:
# print('值不是纯数字')
try:
被监测的代码
except 错误类型 as e:
...
else:
被监测的代码不报错的时候执行
finally:
无论是否报错最终都会执行
# 断言(了解)
name = 'jason'
assert isinstance(name,str)
# 主动报异常
raise 错误类型
# 万能异常
try:
# int('abc')
print(name)
# l = [11]
# l[100]
except Exception:
print('你来啥都行 无所谓')
"""
"""
异常捕获句式和万能异常
1.有可能会出现错误的代码才需要被监测
2.被监测的代码一定要越少越好
3.异常捕获使用频率越低越好
"""
END~
