python第十四课---算法简介二分法,三元表达式,列表生成式,匿名函数及其应用

昨日内容回顾

  • 多层语法糖

    def outter1(func1):   # 8 这时候 wrapper2函数名赋值给了func1  func1>>>wrapper2
        print('加载了outter1')
        def wrapper1(*args, **kwargs):  # 11
            print('执行了wrapper1')      # 12
            res1 = func1(*args, **kwargs)   # 13此时看func1变量名指向的是谁>>wrapper2
            return res1   
        return wrapper1  # 9 outter1函数体运行完,将wrapper1返回了给了假的index变量名 此时index()  等于  wrapper1()
    def outter2(func2):    # 5这时候 wrapper3函数名赋值给了func2  func2>>>wrapper3
        print('加载了outter2')
        def wrapper2(*args, **kwargs):   # 14  依此类推
            print('执行了wrapper2')
            res2 = func2(*args, **kwargs)
            return res2
        return wrapper2     # 6 outte2函数体运行完,将wrapper2返回了给了outter1
    def outter3(func3):   # 2 真正的index的内存地址赋值给了func3   func3>>>index
        print('加载了outter3')
        def wrapper3(*args, **kwargs):
            print('执行了wrapper3')
            res3 = func3(*args, **kwargs)   # 倒数第二步  func3>>>index,所以这一步运行的是真正index函数体的代码
            return res3
        return wrapper3     # 3 outte3函数体运行完,将wrapper3返回了给了outter2
    @outter1          # 7 outter1(wrapper2)  这时候开始执行outter1函数体代码
    @outter2          # 4 outter2(wrapper3)  这时候开始执行outter2函数体代码
    @outter3        # 1 先把真正的index传给outter3变成   outter3(index)
    def index():
        print('from index')    # 最后一步,不考虑返回值的情况下
    index()       # 10 index()等于 wrapper1()  此时执行wrapper1函数体代码
    

image

  • 有参装饰器
    就是在原来无参装饰器的基础上再套一层自定义函数,这时候就可以在最外层的的装饰器函数的括号里进行传参,不会影响被装饰函数体代码的正常运行。

    def outer(func_name):
        def inner(*args,**kwargs):
            res = func_name(*args, **kwargs)
    		  return res
        return inner
    
    def outer_plus(others1,others2):
        def outer(func_name):
            def inner(*args,**kwargs):
                res = func_name(*args, **kwargs)
                return res
            return inner
       	 return outer
    @outer_plus(1,2)
    def index():
        pass
    
  • 装饰器修复技术

    from functools import wraps    # 加两行代码  1
    def outer(func_name):
        @wraps(func_name)          # 2
        def inner(*args,**kwargs):
            res = func_name(*args, **kwargs)
    		  return res
        return inner
    
  • 递归函数

    1.函数的递归调用
    	python中有最大递归深度 1000
    2.递归函数
      递推、回溯
      每次递归都要比上一次简单 并且需要有一个明确的结束条件
      函数自己调自己!!!并且每次重复都要比上一次简单!!!并且需要有一个明确的结束条件!!!
    

今日内容概要

  • 作业讲解
  • 算法简介及二分法
  • 三元表达式
  • 各种生成式
  • 匿名函数
  • 重要内置函数
  • 常见内置函数

今日内容详细

作业讲解

1.利用有参装饰器编写多种用户登录校验策略
# 1.利用有参装饰器编写多种用户登录校验策略
"""
1.直接写死的  jason 123
2.数据来源于列表 ['jason|123','kevin|321','tony|222']
3.数据来源于文件 jason|123\n tom|321\n
"""
def login_auth(condition):
    def outer(func_name):
        def inner(*args, **kwargs):
            # 获取用户名和密码
            username = input('username>>>:').strip()
            password = input('password>>>:').strip()
            # 判断校验的策略
            if condition == 'absolute':
                if username == 'jason' and password == '123':
                    res = func_name(*args, **kwargs)
                    return res
                else:
                    print('用户名或密码错误')
            elif condition == 'list_type':
                user_list = ['jason|123', 'tony|321', 'kevin|222']
                user_data = f'{username}|{password}'
                if user_data in user_list:
                    res = func_name(*args, **kwargs)
                    return res
                else:
                    print('用户名或密码错误')
            elif condition == 'file_type':
                with open(r'userinfo.txt', 'r', encoding='utf8') as f:
                    for line in f:
                        real_name, real_pwd = line.split('|')
                        if real_name == username and real_pwd.strip('\n') == password:
                            res = func_name(*args, **kwargs)
                            return res
			else:
				print('用户名或密码错误')
        return inner

    return outer

@login_auth('absolute')
def index(*args, **kwargs):
    print('from index')

@login_auth('list_type')
def func(*args, **kwargs):
    print('from func')

@login_auth('file_type')
def foo(*args, **kwargs):
    print('from foo')

index()
func()
foo()


2.利用递归函数依次打印列表中每一个数据值
	l1 = [1,[2,[3,[4,[5,[6,[7,[8,]]]]]]]]
思考:
    """
    1.for循环l1里面的数据值
    2.如果是数字 则打印
    3.如果是列表 则循环
    4.for循环小列表里面的数据值
    5.如果是数字 则打印
    6.如果是列表 则循环
    7.for循环小小列表里面的数据值
    8.如果是数字 则打印
    9.如果是列表 则循环
    """
补充知识:判断第一个数据值是不是属于第二个参数指定的数据类型
print(isinstance(123, int))       # 判断123是不是整型
print(isinstance(123, str))  

---------------------------------------------------------------------------
    def get_num(l1):
        for i in l1:  # 递归函数需要结束条件 这里巧在for循环接收到空的能够被for循环的数据时 自动不执行
            if isinstance(i,int):
                print(i)
            else:
                return get_num(i)

    get_num(l1)

image

算法简介及二分法

1.什么是算法
	算法就是解决问题的有效方法 不是所有的算法都很高效也有不合格的算法
2.算法应用场景
	推荐算法(抖音视频推送 淘宝商品推送)
	成像算法(AI相关)......
 	几乎涵盖了我们日常生活中的方方面面
3.算法工程师要求
	待遇非常好 但是要求也非常高
4.算法部门
	不是所有的互联网公司都养得起算法部分 只有大型互联网公司才有
	算法部门类似于药品研发部分
5.二分法
	是算法中最简单的算法 甚至都称不上是算法
    
"""
二分法使用要求
    待查找的数据集必须有序
二分法的缺陷
    针对开头结尾的数据 查找效率很低
常见算法的原理以及伪代码
    二分法、冒泡、快拍、插入、堆排、桶排、数据结构(链表 约瑟夫问题 如何链表是否成环)
"""
l1 = [12, 21, 32, 43, 56, 76, 87, 98, 123, 321, 453, 565, 678, 754, 812, 987, 1001, 1232]
# 查找列表中某个数据值
# 方式1:for循环  次数较多
# 方式2:二分法 不断的对数据集做二分切割
'''代码实现二分法'''
# 定义我们想要查找的数据值
# target_num = 987
代码实现:
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):          # 9 注意函数定义阶段括号里l1与target_num 就只是一个变量名而已,函数调用阶段括号里面实参输什么值,该值就会与这两个形参变量名绑定!!!!!这也是后面递归重新运行函数体代码时,实参输入的值又会与这两个形参变量名重新绑定!!!所以下面的代码没循环一次后,再运行时l1都绑定一个新的值!!!
    if len(l1) == 0:                     # 10 添加一个结束条件
        print('很抱歉 没找到')
        return              # 注意!!函数体代码遇到return就直接结束了,这个地方漏了return后,当输入的目标值不在列表里面时,代码就会报错,因为循环切到最后最后列表空掉了,len()的结果就是0了,空列表是不能索引的,就会一直报错!!!
    middle_index = len(l1) // 2           # 1.获取列表中间索引值
    if target_num > l1[middle_index]:      # 2.比较目标数据值与中间索引值的大小
        right_l1 = l1[middle_index + 1:]   # 3.切片保留列表右边一半
        print(right_l1)     # 打印的目的只是为了看一下每次切割列表变成什么样子了!!
 # 4.针对右边一半的列表继续二分并判断 >>>:考虑用递归函数
        return get_middle(right_l1, target_num)

    elif target_num < l1[middle_index]:   # 5.比较目标数据值与中间索引值的大小
        left_l1 = l1[:middle_index]       # 6.切片保留列表左边一半
        print(left_l1)
# 7.针对左边一半的列表继续二分并判断 >>>:用递归函数
        return get_middle(left_l1, target_num)
		
    else:                                       # 8.
        print('恭喜你 找到了!!!')
get_middle(l1, 987)         # 最后调用运行递归函数并将初始的列表与目标值最为实参传进去
get_middle(l1, 2000)   
get_middle(l1, 12)

# 这样这个一整篇代码就可以实现了不同列表与不同目标值都适用的功能!!!

image

三元表达式 是为了简化代码的!!!!

# 简化步骤1:代码简单并且只有一行 那么可以直接在冒号后面编写
name = 'jason'
if name == 'jason':print('老师')
else:print('学生')


# 简化步骤2:
# 三元表达式!!!
res = '老师' if name == 'jason' else '学生'
print(res)          # 如果要接收if选择判断后的值的话,要用变量名接收一下

语法结构:!!!

表达式1 if 条件表达式 else 表达式2
条件成立则使用表达式1
条件不成立则使用表达式2

当结果是二选一的情况下!!! 使用三元表达式较为简便!!!
并且不推荐多个三元表达式嵌套!!!!

image

各种生成式/表达式/推导式 是为了简化代码的!!!

name_list = ['jason', 'kevin', 'oscar', 'tony', 'jerry']
需求:给列表中所有人名的后面加上_NB的后缀
普通方法:
for循环
# new_list = []                    建立一个空列表
# for i in name_list:
#     data = f'{i}_NB'          3
#     new_list.append(data)     4   也可以用new_list.append(i+'_NB')代替3与4两步  字符串之间支持直接相加的,合成的字符串,添加到空列表里面去。
# print(new_list)      for循环完了,新列表里面也都加进去了

列表生成式() 这个最重要!!!!:

先看for循环的对象!!!
每次for循环之后!!!
再看for关键字前面的操作!!!
new_list = [name + "_NB" for name in name_list]
print(new_list)

image
.

列表复杂情况1: for i in list1 if 只能for in if 连用,不能再加其他的了
name_list = ['jason', 'kevin', 'oscar', 'tony', 'jerry']
new_list = [name + "_NB" for name in name_list if name == 'jason']
print(new_list)
['jason_NB']

new_list = [name + "_NB" for name in name_list if name == 'jerry']
print(new_list)
['jerry_NB']

先for循环,再if判断,条件成立才执行,for关键字前面的操作!!!
相当于for关键字前面的操作代码是if判断后的子代码!!!所以如果if条件不符合,那就继续for循环再判断,只要if条件不符合,就一直for循环完。

.

列表复杂情况2:三元表达式与列表生成式结合
name_list = ['jason', 'kevin', 'oscar', 'tony', 'jerry']
new_list = ['大佬' if name == 'jason' else '小赤佬' for name in name_list if name != 'jack']
print(new_list)
三元表达式: '大佬' if name == 'jason' else '小赤佬'
列表生成式: for name in name_list if name != 'jack'        != 不等于的意思
先执行列表生成式--符合if的条件判断后--再执行三元表达式
['大佬', '小赤佬', '小赤佬', '小赤佬', '小赤佬']

image

字典生成式 了解

s1 = 'hello world'
for i,j in enumerate(s1,start=100):   # 默认从0开始的编号,start=50,就默认从50开始
	print(i,j)

d1 = {i: j for i, j in enumerate('hello')}    # 括号里面也可以放列表,字典等数据类型
print(d1)
还是先执行右边的for循环,i代表的是编号,j是for循环出来的值,再赋值给i:j,这样每循环一次就有了一组i:j的数据,这些数据又在字典括号里面,所以就自动变成字典里的数据了。
enumerate这个方法的作用是:能够帮你在for循环时,还能够帮你在for循环出的值前面在加一个默认从0开始的编号,然后两个数据形成一个元组。还可以通过改变start=n后面的数字n来改变默认开始的数字,来实现从n开始的编号,元组里的数据再赋值给for前面的i: j

image
.相当于for--enumerate 每循环一次造出一个元组后解压赋值给了变量i与j
image
.
image
image

集合生成式

和列表的生成式语法一致,把[]换成{}就行了
res = {i for i in 'hello'}
print(res)

image

元组生成式>>>:没有元组生成式 下列的结果是生成器(后面讲)

# res = (i+'SB' for i in 'hello')
# print(res)
# for i in res:
#     print(i)

匿名函数 也是为了简化代码的!!!

没有名字的函数!!!所以步能使用def关键字了
需要使用关键字lambda!!!

主要用在一些比较简单的逻辑功能上!!!
语法结构  :lambda 形参:返回值
匿名函数一般不单独使用!!!
需要配合其他函数一起用!!!

image
简化代码后 就变成了 lambda a,b:a+b
当然也可以传参:先用变量名接收
image

常见内置函数 匿名函数具体使用场景!!!!

就是用来顶替一些简单的函数,再结合一些内置的函数一起使用!!!

map()
1.map()          映射           重要!!!
    l1 = [1, 2, 3, 4, 5]
    def func(a):
    return a + 1
    res = map(func, l1)         映射 把列表里面的数字全部传到函数里面处理一下,生成一个新的结果
    print(list(res))            res的结果类似于一个工厂,需要用list方法转化一下才能看到真实的值。

利用匿名函数代码简化后:
l1 = [1, 2, 3, 4, 5]
    res = map(lambda x:x+1, l1)   通过这种lambda 形参:返回值,就可以简化了两行代码了!!
    print(list(res))            一定要把res的结果用list转化成列表

image
image
.
.

max() \ min() 找最大值与最小值
max方法默认拿到for循环的结果直接比较。

l1 = [11, 22, 33, 44]
res = max(l1)
print(res)


需求 :假设字典中键是人的名字,值是人的薪资,现在求出里面薪资最高的那个人
	d1 = {
    'zj': 100,
    'jason': 8888,
    'berk': 99999999,
    'oscar': 1
	}
# 不能直接用max(d1),max方法底层原理都是用的for循环,字典for循环出的是字典的键再进行比较的,而不是拿字典的值进行比较的!!!!!!
# 字符串比大小首先是按照位置来比的,其次是按照字母在AscII码里面对应的数字进行比较的!!!!

代码实现:

def func(a):
        return d1.get(a)
res = max(d1, key=func)   max方法自带for循环的,等for循环结束后,拿到全部的循环出的数据让func一个一个的处理后,根据处理后的结果进行比较大小,并返回最大的结果对应的键。key就是个变量名,可以不看。
print(res)


max方法默认参数key是支持传一个函数的(就可以传一个匿名函数了),当默认参数key=none,你不传值时,max方法默认拿到for循环的结果直接比较。但是你一旦给key传值后
这时候max方法就以匿名函数处理后的返回值最为比较大小的依据,比较出大小后,由于max第一次for循环用到还是键,所以最后返回的还是键!!

代码优化:max方法for循环出字典d1中的键,
    res = max(d1, key=lambda k: d1.get(k))
    print(res)

image
image

for循环的是键,但是比的是键对应的值,返回的还是键,谁大就返回谁对应的键
image

优化前:
image

优化后:
image

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)

reduce底层原理还是先for循环,for循环出列表里面的第一个数以后传给匿名函数,此时匿名函数有两个形参,所以第一次a默认等于0,b等于第一次循环出来的值,两个值经过相加后的结果再与第二次for循环的结果22,再传给匿名函数再相加,相加后的结果在与33一起传给匿名函数再相加,以此类推最终将所有的结果加起来了。
lambda a, b: a * b  当加号变成乘号后,第一次行参a默认为1,后面就不用管了。

'''好奇执行流程可以使用debug模式简单看看'''

image

作业

1.整理今日内容及博客
2.好好利用空闲时间查缺补漏
3.附加题
  有下列用户数据
    user_data = {
        '1': {'name': 'jason', 'pwd': '123', 'access': ['1', '2', '3']},
        '2': {'name': 'kevin', 'pwd': '321', 'access': ['1', '2']},
        '3': {'name': 'oscar', 'pwd': '222', 'access': ['1']}
    }
    并有三个函数
        def func1():
            pass
        def func2():
            pass
        def func3():
            pass
    要求:调用上述三个函数的时候需要从user_data中校验用户身份是否正确
    并获取当前登录用户拥有的可执行函数功能编号即键access对应的功能编号列表
    func1是1、func2是2、func3是3
    并且一旦用户登录成功之后后续函数的调用不再校验用户身份
    请思考如何获取函数功能编号 如何校验用户身份 如何校验权限
    ps:装饰器知识         附赠:实现上述主体功能即可 其他扩展优化功能可暂且不写


'''
1.先编写校验用户身份的装饰器
2.然后再考虑如何保存用户登录状态
3.再完善各种需求
'''
user_data = {
    '1': {'name': 'jason', 'pwd': '123', 'access': ['1', '2', '3']},
    '2': {'name': 'kevin', 'pwd': '321', 'access': ['1', '2']},
    '3': {'name': 'oscar', 'pwd': '222', 'access': ['1']}
}
posted @   tengyifan  阅读(39)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示