一 lambda 匿名函数
为了解决一些简单的需求而设计的一句话函数
# 计算 n 的 n次方 def func(n):
return n**n
print(func(10)) f = lambda n:n**n
print(f(10))
lambda 表示的是 匿名函数,不需要用 def 声明,一句话就可以声明出一个函数
语法:
l函数名 = lambda 参数:返回值
注意:
1.返回值可以是一个,也可以是多个,多个 的时候用 逗号 隔开 在 元祖 () 里边
2.lambda 不管多复杂 只能写 一行 , 执行完毕 返回数据
3.lambda 和正常 函数一样 ,返回值 可以 是 任意 数据类型
匿名函数并不是说一定没有名字. 这里前面的变量就是一个函数名. 说他是匿名原因是我们通
过__name__查看的时候是没有名字的. 统一都叫lambda. 在调用的时候没有什么特别之处.像正常的函数调用即可
二 sorted 排序函数
语法:
sorted(iterable,key = None,reverse=False)
iterable :可迭代对象
key = 排序规则(排序函数) 在 sorted 内部 会将 可迭代对象中的 每一个 元素传递给 这个函数的参数
根据 函数运算的 结果进行 排序
reverse; 是否是 倒序 True 倒序 False 正序
lst = [1,5,8,9,2,6,4,3,7]
lst1 = sorted(lst)
print(lst) # [1, 5, 8, 9, 2, 6, 4, 3, 7] 原列表不变
print(lst1) # [1, 2, 3, 4, 5, 6, 7, 8, 9] 返回的列表是经过排序的 dic = {1:"a",3:"b",2:"c"}
dic1 = sorted(dic)
print(dic) # {1: 'a', 3: 'b', 2: 'c'}
print(dic1) # [1, 2, 3] 如果是字典,返回经过排序的 key
# 和 函数 组合使用
lst = ["张曼玉","邱淑贞","朱茵","你","上官寒冰"]
def func(s):
return len(s) print(sorted(lst,key=func))
# ['你', '朱茵', '张曼玉', '邱淑贞', '上官寒冰'] # 和 lambda 组合使用
lst = ["张曼玉","邱淑贞","朱茵","你","上官寒冰"] lst1 = (sorted(lst,key = lambda s:len(s)))
print(lst1) # ['你', '朱茵', '张曼玉', '邱淑贞', '上官寒冰']
lst = [{"id":1, "name":'alex', "age":18},
{"id":2, "name":'wusir', "age":16},
{"id":3, "name":'taibai', "age":17}] # 按照年龄对学生进行排序 func = sorted(lst,key=lambda dic:dic["age"])
print(func)
三 filter() 筛选函数
语法:
filter(function,iterable)
function:用来筛选的函数,在 filter 中 会自动的吧 iterable 中的 元素传递个i function,然后根据 function返回
的 True 或者 False 来判断是否保留 此项数据
iterable : 可迭代对象
#筛选所有的 偶数
lst = [1,2,3,4,5,6,7,8,9]
l = filter(lambda x:x % 2 == 0,lst)
print(l) # <filter object at 0x013E7690>
print(list(l)) # [2, 4, 6, 8] lst = [{"id":1, "name":'alex', "age":18},
{"id":2, "name":'wusir', "age":16},
{"id":3, "name":'taibai', "age":17}] # 筛选年龄大于 16 的数据
lst1 = filter(lambda dic:dic["age"]>16,lst)
print(list(lst1)) # [{'id': 1, 'name': 'alex', 'age': 18}, {'id': 3, 'name': 'taibai', 'age': 17}]
四 map() 映射函数
语法:
map(function,iterable) 可以对 可迭代对象中的 每一个 元素 进行映射 ,分别取执行 function
# 计算列表中 每个元素的 平方,返回新列表
# 1.和函数 组合 使用 def func(s):
return s**2 mp = map(func ,[1,2,3,4])
print(mp) ## <map object at 0x013F7710>
print(list(mp)) ## [1, 4, 9, 16] # 2.和 lambda 组合 使用 print(list(map(lambda i:i**2,[1,2,3,4])))
# [1,4,9,16] # 计算两个 列表中 相同 位置的数据的 和 lst = [1,2,3,4,5]
lst1 = [5,4,3,2,1] print(list(map(lambda x,y:x+y,lst,lst1))) # [6, 6, 6, 6, 6]
五 reduce() 通过某个函数,累计按顺序计算列表中的值 可以 算 累加 累乘 等等吧
python2.x 中 直接 import reduce
python3.x 中 from functools import reduce
from functools import reduce
def func(x,y):
return x + y # reduce 的使用方法
# reduce(函数名,可迭代对象) # 这两个参数必须都要有,缺一个不行
ret = reduce(func,[3,4,5,6])
print(ret) reduce 的作用是 先把列表中的 前两个元素取出计算一和值,然后临时保存
接下来用这个零时保存的值 和 列表中的下一个 再计算,以此类推 # 注意 我们放进去的可迭代对象没有 更改
from functools import reduce # 导入reduce 模块 # 和 lambda 组合 使用 print(reduce(lambda x,y:x*y,[1,2,3,4])) #
六 zip() 拉链函数
zip(*iterables) 生成一个 迭代器(迭代器本质是 生成器),它聚合了 可迭代对象的 每个元素
返回 一个 由 元祖组成的 迭代器,其中 第 i 个元祖 包含 来自每个参数序列 或 可迭代对象的 第i个元素,
当最短的 可迭代对象被 输出时,该 迭代器完成
# 原理如下
def zip(*iterables):
# zip("ABCD","xy") ---> Ax By
sentinel = object()
itetators = [iter(it) for it in iterables]
while itetators:
result = []
for it in itetators:
elem = next(it,sentinel)
if elem is sentinel:
return
result.append(elem)
yield tuple(result) f = zip([1,2,3],[4,5,6,7]) print(f.__next__()) # (1,)
print(f.__next__()) # (1, 4)
print(f.__next__()) # (2,)
print(f.__next__()) # (2, 5)
x = [1,2,3,4]
y = ["张曼玉","邱淑贞","张敏"]
z = [11,22,33,44,55] print(list(zip(x,y,z)))
# [(1, '张曼玉', 11), (2, '邱淑贞', 22), (3, '张敏', 33)] print(list(zip(*zip(x,y,z))))
# [(1, 2, 3), ('张曼玉', '邱淑贞', '张敏'), (11, 22, 33)]
# * 的作用是把上面生成的 迭代器 又 再次 拉链式的 组合了该 迭代器中的 元素
lst = [1,2,3,4,5,6]
lst1 = ["anglobay","haha","hahag","张敏","邱淑贞"]
tu = ("**","***","****","******") b = filter(lambda x:x[0] > 2 and len(x[2]) > 4,zip(lst,lst1,tu))
print(list(b)) # [(4, '张敏', '******')]
七 递归函数 在函数中调用函数本身,就是递归
递归是什么
在数学和计算机科学中,递归指由一种(或多种)简单的基本情况定义的一类对象或方法,
并规定其他所有情况都能被还原为其基本情况。
递归的三要素
- 一个问题的解可以分解为几个子问题的解
- 这个问题与分解之后的子问题,除了数据规模不同,求解思路完全一样
- 一定存在终止递归的条件
关键点
- 写出递推公式
- 找到终止条件
- 将递推公式转化为代码
递归代码要警惕堆栈溢出
函数调用会使用栈来保存临时变量,每调用一个函数,都会将临时变量封装为栈帧压入内存栈,等函数执行完成返回时,才出栈。系统栈或者虚拟机栈空间一般都不大,如果递归求解的数据规模很大,调用层次很深,一直压入栈,就会有堆栈溢出的风险。
如何避免堆栈溢出?
- 在代码中限制递归调用的最大深度,当递归调用超过一定深度,比如1000之后,就不再继续往下递归了,直接返回报错。但是如果递归深度比较大,这种方法就不太适用。
- 采取循环的方式来解决,将需要的数据在关键的调用点保存下来使用。简单的说,就是用自己的数据保存方法来代替系统递归调用产生的堆栈数据。
递归代码要警惕重复计算
使用递归的时候,还会出现重复计算的问题。为避免重复计算,我们可以通过一个数据结构(比如散列表)来保存已经求解过的递归函数值 f(k),当递归调用到 f(k) 时,先看下是否已经求解过了,如果是,则直接从散列表中取值返回,不需要重复计算,这样就能避免重复计算了。
内容小结
- 递归是一种非常高效、简洁的编程技巧。
- 只要是满足“递归三要素”的问题,就可以通过递归代码来解决。
- 编写递归代码的关键点在于:写出递推公式,找出终止条件,然后再翻译成递归代码。
- 递归代码虽然简洁高效,但是也存在很多弊端,如:堆栈溢出、重复计算、函数调用耗时多、空间复杂度高等等,在使用递归时,一定要控制好这些副作用。
def func():
print("我是func")
func()
fucn() # 在python 中,官方解释 递归最大深度1000,但是永远不会跑到1000
# 我实测 998 # 怎么测的 呢?? 其实很简单,就是利用累加 def func(n):
print(n)
n += 1
func(n)
func(1)
递归的应用:
我们可以使用递归来遍历各种树形 结构,比如我们的文件夹系统
# 引入os 模块
import os def func(filepath,n):
files = os.listdir(filepath) # 获取到当前文件夹的所有文件
for fi in files: # 遍历文件夹中的 内容,这里获取到的是本层文件名
fi_d = os.path.join(filepath,fi) # 加入文件夹,获取到文件夹 + 文件
if os.path.isdir(fi_d): # 如果该路径下的是文件夹
print("\t"*n,fi) # 打印出文件名
func(fi_d,n +1) # 继续进行相同的 操作
else:
print("\t" * n, fi) # 递归出口,最终在这里隐含着 return
# 递归 遍历 d盘目录下 所有文件
func("d:/learn-py",0)
八 二分查找
每次查找能够排除掉一半 的数据,查找的效率 非常高,但是局限性比较大,必须是有序序列才可以用二分法
要求: 查找的序列 必须是 有序序列
# 二分查找 ---- 非递归算法
lst = [1,2,3,4,5,6,7,8,9,11,22,33,44,55,66,77,88,99,100,101,111,222,333]
num = int(input("输入你要查找的数字:"))
left = 0
right = len(lst) - 1
count = 1
while left <= right:
middle = (left + right) // 2
if num < lst[middle]:
right = middle - 1
elif num > lst[middle]:
left = middle + 1
else:
print(count)
print(middle)
break
count += 1 else:
print("不存在")
# 普通 递归版本 二分法
# 利用 索引切片,切了列表,不符合的 切掉
# 当 列表 切完了之后,就可以判断了
# 很难计算 位置
lst = [1,2,3,4,5,6,7,8,9,11,22,33,44,55,66,77,88,99,100,101,111,222,333] num = int(input("输入你要查找的数字:"))
def func(n,lst):
left = 0
right = len(lst) - 1
if lst != []:
middle = (left + right) // 2
if num > lst[middle]:
func(n,lst[middle + 1:])
elif num < lst[middle]:
func(n,lst[:middle])
else:
print("找到了")
return None
else:
print("没找到")
return None
print(func(num,lst))
# 判断 num 是不是在 列表中,可以返回 num 所在的 位置
# 用 递归,要找到设么是 可变的,什么是不可变的 \
# 列表不动
lst = [1,2,3,4,5,6,7,8,9,11,22,33,44,55,66,77,88,99,100,101,111,222,333] num = int(input("输入你要查找的数:"))
def func(n,lst,left,right):
if left <= right:
middle = (left + right) // 2
if n > lst[middle]:
left = middle + 1
return func(n,lst,left,right)
elif n < lst[middle]:
right = middle - 1
return func(n,lst,left,right)
else:
print("找到了")
return middle
else:
print("找不到")
return -1
ret = func(num,lst,0,len(lst) - 1)
print(ret)
# 还有一种查找方法
# 堪称最快之 查找方法 ,此方法 不需要 列表是 有序的 lst = [1,2,55,66,88,3,44,6,5,7,8,111,222,333]
new_lst = []
for i in range(334):
new_lst.append(i)
for el in lst:
new_lst[el] = 1
num = int(input("输入你要查找的数字:"))
if new_lst[num] == 0:
print("不存在")
else:
print("存在")