【2022-07-10】上周内容回顾
上周内容回顾
函数参数补充知识
*与**在实参中的作用
*号在实参中,会将*号后面的数据类型,用for循环的方式依次进行取值,并传输给函数使用,数据类型可以是列表、字符串、字典、元组,
其中字典在取值的时候,只有键会参与,值不参与
**只针对字典,它会将字典的键值对取出来,当成关键字参数的形式传输给函数
 
def function(*args, **kwargs):
    print(args)
    print(kwargs)
function()                                      # ()   {}
function([11, 22, 33, 44, 55])                  # ([11, 22, 33, 44, 55],)   {}
l1 = [66, 77, 88, 99, 123]
function(l1[0], l1[1], l1[2], l1[3], l1[4])     # (66, 77, 88, 99, 123)   {}
function(*l1)                                   # (66, 77, 88, 99, 123)   {}
s1 = 'good job'
function(*s1)                                   # ('g', 'o', 'o', 'd', ' ', 'j', 'o', 'b')     {}
dict1 = {'1': '张三', '2': '30'}
function(*dict1)                                # ('1', '2')   {}
dict2 = {'username': '李四', 'pwd': 666} 
function(**dict2)                               # ()  {'username': '李四', 'pwd': 666}
function(username='李四', pwd=666)              # ()  {'username': '李四', 'pwd': 666}
命名关键字参数
命名关键字参数需要放在形参*args的后面,形参**kwargs的前面,不然就会报错
def function(x, y, *args, z):
    print(x, y, args, z)
function(11, 22, 33, 44, 55, 66)              # 报错:TypeError: function() missing 1 required keyword-only argument: 'z'
function(11, 22, 33, 44, 55, z=666)           # 11 22 (33, 44, 55) 666
def function(x, y, *args, z, **kwargs):
    print(x, y, args, z, kwargs)
function(11, 22, 33, 44, 55, z=777, name='张三', age=888)  # 11 22 (33, 44, 55) 777 {'name': '张三', 'age': 888}
名称空间与作用域
名称空间
名称空间就是用来存放变量名与数据值之间绑定关系的地方
username = '张三'
首先在内存中申请一块内存空间用于存储数据值张三,然后绑定给变量名username
变量名username与数据值张三的绑定关系就会存储到名称空间里,后续如果需要使用变量名都是去名称空间里查找并锁定对应的数据值
del username 删除的不是数据值,而是变量名以及变量名与数据值之间绑定的关系
username = '张三'
print(username)
print(username)
print(username)
del username
print(username)           #  NameError: name 'username' is not defined
名称空间分类
内置名称空间
python解释器运行就会创建的名称空间,写代码过程中可以直接使用的名字都在该空间内。eg: len() print() input().....
全局名称空间
py文件运行代码过程中产生的名字都会存入该名称空间,如逻辑代码的变量名,分支结构的变量名,循环结构的变量名,以及定义函数的函数名
局部名称空间
函数体代码运行过程中产生的名字都会存入该名称空间
名字的查找顺序
查找名字之前一定要先看自己在哪个名称空间
1.当前在全局名称空间
	全局名称空间	 >>>:   内置名称空间
2.当前在局部名称空间
	局部名称空间   >>>:  全局名称空间  >>>:	内置名称空间
名字的查找顺序默认情况下不能颠倒只能是	局部>>>:全局>>>:内置
名字的存活周期
存活周期
  1.内置名称空间
  	python解释器运行 产生
    python解释器关闭 销毁
  2.全局名称空间
  	py文件开始运行 产生
    py文件运行结束 销毁
  3.局部名称空间
  	函数体代码开始运行 产生
    函数体代码运行结束 销毁
作用域
1.内置名称空间
	在程序任意位置都可以使用(全局有效)
2.全局名称空间
	在程序任意位置都可以使用(全局有效)
3.局部名称空间
	在各自的局部空间可以使用(局部有效)
global关键字与nolnocal关键字
gloabl关键字:局部修改全局不可变类型
# x = 111
# def index():
#     # x = 222  # 并不是在修改全局的x 而是在局部名称空间中创建了一个新的x
#     # 如果想要在局部名称空间中修改全局名称空间中的名字 那么需要使用关键字申明
#     global x  #  修改的是全局x而不是产生新的x
#     x = 666
# index()
# print(x)
l1 = [111, 222, 333]
def index():
    l1.append(444)
index()
print(l1)
"""
如果想要在局部修改全局的不可变类型
    需要提前加关键字global申明
如果想要在局部修改全局的可变类型
    不需要加关键字global申明
"""
def index():
    x = 111  # 在index的局部产生一个x=111
    l1 = [11, 22, 33]
    def f1():
        # x = 222  # 在f1的局部产生一个x=222
        # print(x)
        # 局部名称空间嵌套 内层修改外层
        # nonlocal x
        # x = 333
        l1.append(44)
    f1()
    print(x)
    print(l1)
index()
局部名称空间嵌套的情况下 内层如果想要修改外层
    情况1数据是不可变类型
        需要使用关键字nonlocal
    情况2数据是可变类型
        不需要使用关键字nonlocal
局部名称空间的复杂情况
x = 111
如果函数没有被调用 那么不要去管函数体代码有多复杂,先跳过
def f1():
    x = 222
    def f2():
        x = 333
        def f3():
            print(x)  # 检测语法的时候 发现f3的局部名称空间将来会有x 所以查找的时候就跟f3的局部名称空间要(特例 可以忽略)
            x = 444 
            # print(x)
        f3()
    f2()
f1()
局部名称空间之间如果不是嵌套关系 那么互不干涉!!!
def index1():
    name = 'jason'
def index2():
    age = 18
    print(name)  # 报错
index1()
index2()
函数名的多种使用方式
# def index():
#     print('from function index')
# 用法1:函数名可以当做变量名赋值
# print(index)
# res = index  # 让res也指向函数体代码
# print(res)
# res()  # index()
# 用法2:函数名还可以当成函数的实参
# def index():
#     print('from index')
# def func(a):
#     print('from func')
#     print(a)
#     a()
# func(index)
# 用法3:函数名还可以当做函数的返回值
# def func():
#     print('from func')
#     return index  # 将函数名当做返回值
# def index():
#     print('from index')
# res = func()  # res接收函数名
# print(res)  # 指向的是index函数的内存地址
# res()  # index()
# 用法4:函数名可以作为容器类型的元素
'''容器类型:内部可以存放多个元素的数据类型>>>:列表、元组、字典'''
# def index():
#     print('from index')
# l1 = [11, 22, 33, 44, index]
# print(l1)
# l1[-1]()  #  index()
闭包函数简介
1.定义在函数内部的函数
2.内部函数使用了外部名称空间中的名字
PS:只有符合上述两个特征的函数才能称之为是闭包函数
def function(username):    # 形参username,当被调用时会与实参发生临时绑定关系,以什么等于什么的方式,会在function局部名称空间存放一个名字
    # username = '张三'
    def index():
        print(username)
    return index
# 上述就是一个闭包函数,首先index是定义在function函数内部的,其次username是属于function局部名称空间的名字
# 那么如何在全局名称空间里调用index呢,即从全局名称空间里调用局部名称空间名字index
# 明确当前在哪个名称空间里,然后按照名字的查找顺序:局部名称空间——全局名称空间——内置名称空间
# res = function()
# print(res)                               # <function function.<locals>.index at 0x000001800F267820>
# res()                                    # 张三
res = function('张三')                     # username = '张三'
print(res)                                 # <function function.<locals>.index at 0x0000024A26BB7820>
res()                                      # 张三
闭包函数,外层函数的名称空间不会随着外层函数体代码运行结束后关闭,直到整个py文件都不在进行调用内部名称空间里的其他闭包函数时
它会自我进行检测,看看是否会被调用,如果有则不关闭,如果没有则自动关闭
闭包函数的实际应用
给函数体代码传值的方式一:通过形参
def function(xxx):
    print(xxx)
function(666)
给函数体代码传值的方式二:闭包函数
def index(username):                  # 1.定义一个函数index
    # username = 'Lisa'               # 3.并且在index局部名称空间里存放了一个username,让它指向了数据值lisa
    def function():                   # 4.在index的名称空间里也定义了一个function函数
        print(username)  
    return function                   # 5.把function返回到全局名称空间里
# 6.res就是function函数名
res = index('lisa')                  # 2.执行index函数调用,把lisa传给函数index的形参username,产生一个index的局部名称空间
                                     
res()  # 7. 开始调用function函数,然后在function局部空间里找username,如果没有就在外层即index的局部名称空间里找username,此时得到的结果就是Lisa                         
res1 = index('tony')  # 8.把之前的名称空间清除,重新调用index函数,重复上面的步骤
res1()                               # tony
装饰器简介及时间戳
装饰器的作用:在不改变被装饰对象原有的调用方式和内部代码的情况下给被装饰对象添加额外的功能
装饰器的原则:对修改封闭,对扩展开放
时间戳的使用:
import time
print(time.time())                   # 1657028359.8169787
# 时间戳(秒数):当前距离1970年1月1日0时0分0秒所经历的秒数
# 实际应用:统计代码的运行时间
start_time = time.time()
for i in range(100000):
    print(i)
end_time = time.time()
print('for循环的执行时间是:%s' % (end_time - start_time))        # for循环的执行时间是:0.8020210266113281
time.sleep(5)
"""让程序原地等待五秒钟"""
print('晚上好呀')                # 指针停留五秒钟后打印   晚上好呀
装饰器推导流程
import time
def index():
    time.sleep(4)
    print('please tell me what is the time for index')
# 在不改变index调用方式和内部代码的情况下,统计index的执行时间
# start_time = time.time()    		    # 在调用index函数之前获取时间戳
# index()  						      # 调用index函数
# end_time = time.time()
# print(end_time - start_time)          # please tell me what is the time for index       4.008287191390991
# 1.缺陷1  如果有多个相同的函数需要被统计时间,则需要重复编写执行代码
# 解决措施:封装成函数
def get_time():
    start_time = time.time()
    index()   # 调用index函数
    end_time = time.time()
    print('函数的执行时间是:', end_time - start_time)
# get_time()                               # please tell me what is the time for index  函数的执行时间是: 4.007498025894165
# get_time()                               # please tell me what is the time for index  函数的执行时间是: 4.007647275924683
# get_time()                               # please tell me what is the time for index  函数的执行时间是: 4.013478994369507
# 2.缺陷2  如果有多个不同的函数需要统计时间,那么封装函数的措施就不够完善了
# 解决措施:可以通过给函数体传形参的方式来打破限制
def home():                # 1.定义一个函数home
    time.sleep(5)
    print('please tell me what is the time for home')
def get_time(xxx):         # 2.定义一个函数get_time              
    start_time = time.time()                     # 在调用index函数之前获取时间戳
    xxx(*args, **kwargs)   # 调用index函数
    end_time = time.time()
    print('函数的执行时间是:', end_time - start_time)
# get_time(index)              # please tell me what is the time for index    函数的执行时间是: 4.008310079574585
# get_time(home)               # please tell me what is the time for home     函数的执行时间是: 5.007116317749023
# 3.缺陷3   不同形参个数的函数,无法兼容统计
# 解决措施   利用*args **kwargs  目前代码中无法实现
def function(a):
    time.sleep(2)
    print('please tell me what is the time for function')
get_time(function)            # 无法直接调用,需要进行传值
# 4.缺陷4  改变了原来的调用方式
# 解决措施  装饰器推导流程
# 4.缺陷4  改变了原来的调用方式
# 解决措施  装饰器推导流程
装饰器初始版本
# 函数体代码需要不确定的数据  有几种给的方式
# 方式一:通过形参的方式进行传参,但是无法实现不改变调用方式
# 方式二:闭包函数
def outer(xxx):
    # xxx = index
    def get_time():         # 2.定义一个函数get_time
        start_time = time.time()                     # 在调用index函数之前获取时间戳
        xxx()   # 调用index函数
        end_time = time.time()
        print('函数的执行时间是:', end_time - start_time)
    return get_time
# res = outer(index)
# res()                      # please tell me what is the time for index   函数的执行时间是: 4.0019402503967285
# res = outer(home)
# res()                      # please tell me what is the time for home    函数的执行时间是: 5.004338026046753
index = outer(index)
index()                      # please tell me what is the time for index   函数的执行时间是: 4.017440319061279
home = outer(home)
home()                       # please tell me what is the time for home    函数的执行时间是: 5.004836082458496
装饰器进阶版本
import time                                          # 针对有参函数与无参函数如何兼容
def outer(xxx):
    # xxx = index
    def get_time(*args, **kwargs):                   # *与**在形参中的使用方式
        start_time = time.time()                     # 在调用index函数之前获取时间戳
        xxx(*args, **kwargs)   # 调用index函数
        end_time = time.time()
        print('函数的执行时间是:', end_time - start_time)
    return get_time
def home():
    time.sleep(3)
    print('what is the time for home')
def index(name):
    time.sleep(2)
    print('what is the time for index')
def function(x,y,z):
    time.sleep(3)
    print('what is the time for function')
home = outer(home)
home()                             # what is the time for home           函数的执行时间是: 3.003410577774048
index = outer(index)        
index('tony')                      # what is the time for index          函数的执行时间是: 2.0139412879943848
function = outer(function)         
function(6,7,8)                    # what is the time for function       函数的执行时间是: 3.015282392501831
装饰器高级版本
import time
def outer(xxx):
    def get_time(*args, **kwargs):
        start_time = time.time()  # 在调用index函数之前获取一下时间戳
        res = xxx(*args, **kwargs)  # 调用index函数
        end_time = time.time()
        print('函数的执行时间是:', end_time - start_time)
        return res
    return get_time
def home():
    time.sleep(2)
    print('from home')
    return '执行home函数之后的返回值'
def index(name):
    time.sleep(1)
    print('from index')
    return '执行index函数之后的返回值'
home = outer(home)
xxx = home()
print(xxx)
index = outer(index)
res = index('jason')
print(res)
# home = outer(home)
# home()
# def func(a,b,c):
#     time.sleep(1)
#     print('from func')
#
# index = outer(index)
# index('jason')
#
# home = outer(home)
# home()
#
# func = outer(func)
# func(1,2,3)
装饰器最终版本(模板)
from functools import wraps
def outer(func_name):
    @wraps(func_name)  # 仅仅是为了让装饰器不容易被别人发现 做到真正的以假乱真
    def inner(*args, **kwargs):
        print('执行被装饰对象之前可以做的额外操作')
        res = func_name(*args, **kwargs)
        print('执行被装饰对象之后可以做的额外操作')
        return res
    return inner
# import time
# def home():
#     time.sleep(1)
#     print('from home')
#     return 'home返回值'
# home = outer(home)
# res = home()
# print(res)
"""
执行home函数之前需要添加校验用户身份的功能
"""
# 装饰器语法糖
import time
@outer  #  home = outer(真正的函数名home)
def home():
    '''我是home函数 我要热死了!!!'''
    time.sleep(1)
    print('from home')
    return 'home返回值'
# help(home)
# print(home)
home()
# def index():
#     '我是index函数 我的功能很强大'
#     pass
#
# help(index)
多层装饰器
"""
语法糖的功能:会自动将下面紧挨着的函数名当做参数传递给@符号后面的函数名(加括号调用)
涉及到多个语法糖装饰一个函数名,从下往上执行,最后一个语法糖才会做重命名操作
"""
def outer1(function1):  # function1 = wrapper2函数名
    print('加载了outer1')  # 第三个打印的语句
    def wrapper1(*args, **kwargs):
        print('执行了wrapper1')  # 第四个打印的语句
        res1 = function1(*args, **kwargs)
        return res1
    return wrapper1
def outer2(function2):  # function2 = wrapper3函数名
    print('加载了outer2')  # 第二个打印的语句
    def wrapper2(*args, **kwargs):
        print('执行了wrapper2')  # 第五个打印的语句
        res2 = function2(*args, **kwargs)
        return res2
    return wrapper2
def outer3(function3):  # function3 = 真正的index函数
    print('加载了outer3')  # 第一个打印的语句
    def wrapper3(*args, **kwargs):
        print('执行了wrapper3')  # 第六个打印的语句
        res3 = function3(*args, **kwargs)
        return res3
    return wrapper3
@outer1  # index = outer1(wrapper2)            index为wrapper1  调用outer1把wrapper2函数名当做参数传进去
@outer2  # wrapper2 = outer2(wrapper3)         调用outer2把wrapper3函数名当做参数传进去
@outer3  # wrapper3 = outer3(真实的index函数名)
def index():
    print('hello word')  # 最后一个打印的语句
index()
#  多层装饰器执行流程
# 1.首先语法糖会自动将下面紧挨着的函数名当做参数传递给@符号后面的函数名(加括号调用)
# 2.outer3加括号调用并且把真正的index函数名传进去
# 3.函数名加括号执行优先级最高,这个时候执行outer3,function3接收了真正的index函数
# 4.接着执行了print('加载了outer3') 它就是第一个打印的语句
# 5.然后在outer3内部定义了一个wrapper3,并返回了wrapper3,这个时候outer3加括号执行后的返回值就是wrapper3
# 6.由于outer3语法糖上面还有一个outer2语法糖,所以不会做重命名操作,直接把wrapper3 = outer3(真实的index函数名)
# 7.于是又触发了语法糖的条件,调用outer2把wrapper3函数名当做参数传进去
# 8.这个时候function2形参指向了wrapper3函数名,然后打印了第二个print语句,print('加载了outer2')
# 9.然后又在outer2内部定义了一个wrapper2,并返回了wrapper2,这个时候outer2加括号执行后的返回值就是wrapper2
# 10.由于outer2上面还有一个语法糖outer1,所以不会做重命名操作,直接把wrapper2 = outer2(wrapper3)
# 11.于是又触发了语法糖的条件,调用outer1把wrapper2函数名当做参数传了进去
# 12.这个时候function1形参指向了wrapper2函数名,然后打印了第三个print语句,print('加载了outer1')
# 13.然后又在outer1里定义了一个wrapper1,并返回了wrapper1
# 14.这个时候语法糖已经没有了,最终就会用被装饰的函数同样的名字来接收outer1(wrapper2)运行后的返回值
# 15.这个时候的index就是wrapper1,执行index()开始调用
# 16.index()就是wrapper1(),所以调用首先执行的是wrapper1,然后打印了第四个print语句('执行了wrapper1')
# 17.接着往下走,遇到赋值符号先看右边,右边是function1,function1现在指向的是wrapper2函数名
# 18.所以打印了第五个print语句('执行了wrapper2')
# 19.往下走又是一个赋值符号,先看右侧function2,function2指向的是wrapper3函数名
# 20.所以打印了第六个print语句('执行了wrapper3')
# 21.往下走又是一个赋值符号,先看右侧function3,function3指向的是真正的index函数名
# 22.所以执行了第七个print语句('hello word')
# 最后的打印结果就是:
# 加载了outer3
# 加载了outer2
# 加载了outer1
# 执行了wrapper1
# 执行了wrapper2
# 执行了wrapper3
# hello word
有参装饰器
# 需求:在使用装饰器进行用户校验时,我可以随意切换数据的来源,无论是字典、列表还是文件
def outer(condition):
    def login_auth(function_name):         # 无法添加更多的形参,只能接收一个被装饰对象的函数名
        def inner(*args, **kwargs):        # 无法添加参数,因为它是专门用来给被装饰器对象传参的
            username = input('please your username>>>:').strip()
            password = input('please your password>>>:').strip()
            # 根据用户需求执行不同的代码
            if condition == '字典':
                print('使用字典作为用户数据来源,进行比对')
            elif condition == '列表':
                print('使用列表作为用户数据来源,进行比对')
            elif condition == '文件':
                print('使用文件作为用户数据来源,进行比对')
            else:
                print('其他操作情况')
        return inner
    return login_auth
@outer('字典')
def index():
    print('hello word')
index()
# 有参装饰器的执行流程
# 1.定义了一个outer函数
# 2.定义了一个index函数
# 3.看到语法糖@outer('字典'),函数名加括号执行优先级最高,所以先执行outer('字典')
# 4.这个时候字典是传输给了condition
# 5.然后执行login_auth
# 6.接着执行return login_auth,并返回login_auth 这个时候就成了语法糖@login_auth
# 7.把index传给login_auth
# 8.定义函数inner,返回inner函数名,将返回的值赋值给index
# 9.执行index函数,并执行打印结果
递归函数简介
递归函数是一个直接或间接调用函数本身的嵌套型函数,每一个递归函数都有递推(递的概念)和回推(归的概念)的过程。递推过程是将一个复杂的大问题一步步分解成简单的过程类似的小问题,而回推过程是在递归历史的基础上,从最后的最简单的小问题开始,结合该层上一层的输入参数与输出结果,按逻辑一步步向上恢复成最初的复杂的大问题。
# 递归函数的概念   在编程语言中,函数直接或者间接调用了函数本身,则该函数称之为递归函数
# 递归调用:直接调用
# def index():                         # 1.先定义一个函数index
#     print('hello word')              # 3.打印hello word
#     index()                          # 4.这又是一个index函数调用,它反复执行调用自己,最后的结果就是报错
# index()                              # 2.调用index函数
# 递归调用:间接调用
# def index():                                    # 1.定义一个函数index
#     print('hello word')                         # 6.打印hello word
#     home()                                      # 7.再次调用home函数,打印from home   依次类推,无限重复
#
#
# def home():                                     # 2.定义一个函数home
#     print('from home')                          # 4.打印from home
#     index()                                     # 5.调用index函数
#
#
# home()                                          # 3.调用home()函数
# Python中允许函数最大递归调用的次数为:1000  官方给出的限制是1000 用代码去验证可能会有些许偏差(996 995...)
# count = 0
# def index():
#     print('hello word')
#     global count
#     print(count)
#     count += 1  # count = count + 1
#     index()
# index()
# import sys
# print(sys.getrecursionlimit())              # 1000  获取递归最大次数
# sys.setrecursionlimit(2000)  # 自定义最大次数
# print(sys.getrecursionlimit()
# def index():
#     print('hello word')
#     global count
#     print(count)
#     count += 1  # count = count + 1
#     index()
# index()
# import sys
# print(sys.getrecursionlimit())              # 1000  获取递归最大次数
# sys.setrecursionlimit(2000)  # 自定义最大次数
# print(sys.getrecursionlimit())
递归函数的使用
"""
递归函数真正的应用场景
    递推:一层层往下寻找答案
    回溯:根据已知条件推导最终结果
递归函数
    1.每次调用的时候都必须要比上一次简单!!!
    2.并且递归函数最终都必须要有一个明确的结束条件!!!
"""
l1 = [1, [2, [3, [4, [5, [6, [7, [8, [9, [10, ]]]]]]]]]]
# 循环打印出列表中所有的数字
# 1.for循环l1里面所有的数据值
# 2.判断当前数据值是否是数字 如果是则打印
# 3.如果不是则继续for循环里面所有数据值
# 4.判断当前数据值是否是数字 如果是则打印
# 5.如果不是则继续for循环里面所有数据值
# 6.判断当前数据值是否是数字 如果是则打印
def get_num(l1):
    for i in l1:
        if isinstance(i,int):
            print(i)
        else:
            get_num(i)
get_num(l1)
算法之二分法
什么是算法
	算法就是解决问题的方法
算法永远都在精进 但是很少有最完美的算法
	算法很多时候可能没什么用
    	小公司一般不会有算法工程师 只有大公司才会有
   			算法工程师待遇很高 但是产出很少 甚至几年几十年都没有成果
          有点相当于科研人员
很多大型互联网面试都喜欢问算法
	平时学有余力可以简单看看(临时抱佛脚)
    	二分法 快拍 插入 堆排 链表 双向链表 约瑟夫问题
二分法
	是所有算法里面最简单的算法
    	也有人说二分法不是算法
        
l1 = [11, 23, 32, 45, 65, 78, 90, 123, 432, 467, 567, 687, 765, 876, 999, 1131, 1232]
def get_num(l1, target_num):
    # 添加递归函数的结束条件
    if len(l1) == 0:
        print('不好意思 找不到')
        return
    # 1.先获取数据集中间那个数
    middle_index = len(l1) // 2
    middle_value = l1[middle_index]
    # 2.判断中间的数据值与目标数据值孰大孰小
    if target_num > middle_value:
        # 3.说明要查找的数在数据集右半边  如何截取右半边
        right_l1 = l1[middle_index + 1:]
        # 3.1.获取右半边中间那个数
        # 3.2.与目标数据值对比
        # 3.3.根据大小切割数据集
        # 经过分析得知 应该使用递归函数
        print(right_l1)
        get_num(right_l1, target_num)
    elif target_num < middle_value:
        # 4.说明要查找的数在数据集左半边  如何截取左半边
        left_l1 = l1[:middle_index]
        # 4.1.获取左半边中间那个数
        # 4.2.与目标数据值对比
        # 4.3.根据大小切割数据集
        # 经过分析得知 应该使用递归函数
        print(left_l1)
        get_num(left_l1, target_num)
    else:
        print('找到了', target_num)
# get_num(l1, 999)
get_num(l1, 1000)
"""
二分法缺陷
	1.数据集必须是有序的
	2.查找的数如果在开头或者结尾 那么二分法效率更低!!!
"""
三元表达式
- 概念:在Python中三元表达式是一种语法结构,又称之为条件表达式
- 作用:减少了代码量,在保证代码可执行的情况下,使代码变得更加精简
- 语法结构:条件成立时返回的值(True执行语句) if 条件表达式 else 条件不成立时返回的值(False执行语句)
- 应用场景:三元表达式仅限于二选一的情况下使用,而且不建议嵌套使用
- 注意事项:在python中代码不是精简的越少越好,在精简的过程中还要保证代码的可读性
- 用法举例一:
# 1.定义一个年龄,然后判断是否已成年,如果大于等于18则打印成年,否则打印未成年
# 2.一般写法,使用了六行代码
age = 20
if age >= 18 :
    cn = "成年"
else:
    cn = "未成年"
print(cn)                          # 成年
# 3.三元表达式写法  三行代码
age = 16
cn = '成年' if age >= 18 else '未成年'
print(cn)                         # 未成年
- 用法举例二:
# 1.编写一个函数,比较两个数据值的大小,并返回最大的数据值
# 2.一般写法
def user_max(x, y):
    if x > y:
        return x
    return y
result = user_max(100, 200)
print(result)  # 200
# 3.三元表达式写法
def user_max(x, y):
    return x if x > y else y
result = user_max(666, 777)
print(result)  # 777
列表生成式
- 概念:列表生成式是python内置的非常简单却又强大的可以用来创建list的生成式
- 作用:简化代码,提升代码效率,也可以用来做if判断
# 1.列表生成式
name_list = ['柳宗元', '韩愈', '欧阳修', '苏洵', '苏辙', '苏轼', '王安石', '曾巩']
# 需求:给上述列表中所有的数据值后边加上:唐宋八大家的后缀
# 2.先定义一个空列表
new_list = []
# 3.循环获取列表中的每个数据值
for name in name_list:
    # 4.拼接:唐宋八大家后缀
    new_name = name + ':唐宋八大家'
    # 5.追加到新列表
    new_list.append(new_name)
print(new_list)   # ['柳宗元:唐宋八大家', '韩愈:唐宋八大家', '欧阳修:唐宋八大家', '苏洵:唐宋八大家', '苏辙:唐宋八大家', '苏轼:唐宋八大家', '王安石:唐宋八大家', '曾巩:唐宋八大家']
# 使用列表生成式,一行代码实现上述操作
new_list = [name + ':唐宋八大家' for name in name_list]
print(new_list)    # ['柳宗元:唐宋八大家', '韩愈:唐宋八大家', '欧阳修:唐宋八大家', '苏洵:唐宋八大家', '苏辙:唐宋八大家', '苏轼:唐宋八大家', '王安石:唐宋八大家', '曾巩:唐宋八大家']
# 上述操作,如果在列表生成式中使用了流程控制关键字,那么执行顺序为:
# 1.先执行流程控制,比如上面的for循环,依次进行取值
# 2.然后拿着取到的数据值执行for关键字前面的表达式,即在每个数据值后面都加上一个后缀:唐宋八大家
# 3.这个执行过程所产生的数据值都会默认放在列表里,因为在它的外层就是一个列表
# 列表生成式还支持if判断
new_list = [name + ':唐宋八大家' for name in name_list if name != '苏轼']
print(new_list)    # ['柳宗元:唐宋八大家', '韩愈:唐宋八大家', '欧阳修:唐宋八大家', '苏洵:唐宋八大家', '苏辙:唐宋八大家', '王安石:唐宋八大家', '曾巩:唐宋八大家']
# 上述操作,执行顺序为:
# 1.先执行流程控制for循环,依次进行取值
# 2.把每次取到的数据值先交给后面的if判断,如果判断条件成立结果为True,即'苏轼'不等于'苏轼',那么这个数据值就会被丢弃
# 3.然后依次对每个数据值进行判断,如果成立结果为True,则执行for关键字前面的表达式,即在每个数据值后面都加上一个后缀:唐宋八大家
PS:列表生成式中只能出现for和if,不能出现else,因为for和if都可以结合else使用,else不知道和谁去匹配执行操作
字典生成式
- 概念:Python内置的一种极其强大的生成字典dict 的表达式。返回结果必须是字典
- 作用:简化代码,提升代码效率,也可以用来做if判断
# 2.字典生成式,也可以使用if判断
new_dict = {i: '+1' for i in range(6)}
print(new_dict)           # {0: '+1', 1: '+1', 2: '+1', 3: '+1', 4: '+1', 5: '+1'}
# 上述操作的执行流程为:
# 1.先执行流程控制for循环语句,依次进行取值
# 2.如果后面没有if判断语句,则直接交给for前面的表达式执行
# 3.执行后会反复的往字典里添加键值对,并且产生的数据值都会默认放在字典里,因为它在外层就是一个字典
# 4.字典生成式同样可以进行if判断
new_dict = {i: '+1' for i in range(6) if i == 3}
print(new_dict)          # {3: '+1'}
# 上述操作的执行流程为:
# 1.先执行流程控制for循环,依次进行取值
# 2.把每次取到的数据值先交给后面的if判断,如果判断条件成立结果为True,即'i'等于'3',那么这个数据值就会交给for前面的表达式执行
new_dict = {i: '+2' for i in range(6) if i != 2}
print(new_dict)          # {0: '+2', 1: '+2', 3: '+2', 4: '+2', 5: '+2'}
# 上述操作,执行顺序为:
# 1.先执行流程控制for循环,依次进行取值
# 2.把每次取到的数据值先交给后面的if判断,如果判断条件成立结果为True,即'i'不等于'2',那么这个数据值就会被丢弃
# 3.然后依次对每个数据值进行判断,如果成立结果为True,则执行for关键字前面的表达式,即在每个数据值后面都加上一个后缀:+2
集合生成式
- 概念:集合生成式是python内置的非常简单却又强大的可以用来创建集合的生成式
- 作用:简化代码,提升代码效率,也可以用来做if判断
# 3.集合生成式,也可以使用if判断
new_set = {i for i in range(10)}
print(new_set)          # {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
# 上述操作的执行流程为:
# 1.先执行流程控制for循环语句,依次进行取值
# 2.如果后面没有if判断语句,则直接交给for前面的表达式执行
# 3.执行后产生的数据值都会默认放在字典里,因为它在外层就是一个字典
new_set = {i for i in range(10) if i == 4}
print(new_set)          # {4}
# 上述操作的执行流程为:
# 1.先执行流程控制for循环,依次进行取值
# 2.把每次取到的数据值先交给后面的if判断,如果判断条件成立结果为True,即'i'等于'4',那么这个数据值就会交给for前面的表达式执行
匿名函数
匿名函数就是没有函数名的函数
语法结构	
lambda 形参: 返回值
# 匿名函数
print((lambda a: a + 1)(666))  # <function <lambda> at 0x00000193A311A5E0>    # 667  直接调用
result = lambda a: a + 1
print(result(666))             # <function <lambda> at 0x000001CD4F1CA5E0>    # 667  命名调用
# 普通函数
def index(a):
    return a + 1
print(index)                   # <function index at 0x0000019572E8A5E0>
应用场景
	匿名函数通常都需要配合其他函数一起使用 用于减少代码
常见内置函数
# max 求最大值
# l1 = [100, 200, 3, 5, 7, 666, 777, 888, 99999, 12138]
# result = max(l1)
# print(result)                    # 99999
# dic = {'tony': 100, 'oscar': 300, 'lisa': 99999999, 'zero': 12138888}
# res = max(dic)
# print(res)                        # zero
# 上述操作执行后的打印结果为什么是zero呢?
# 因为我们比较的是字符串,但是字符串在参与比较的时候,它是转换为ASCII码来比较的
"""
A-Z   65-90
a-z   97-122
"""
# print('A' > 'a')                 # False
dic = {'tony': 100, 'oscar': 300, 'lisa': 99999999, 'zero': 12138888}
res = max(dic, key=lambda k: dic.get(k))
print(res)                         # lisa
# 上述操作的执行流程为:
# 1.max底层是for循环,在没有加Key关键字的时候,它就会直接for循环拿字典的键进行比较
# 2.加了Key关键字后,在每一次for循环的时候,拿着循环出来的结果交给了lambda匿名函数
# 3.这个key交给了lambda匿名函数的形参k,这个时候K就等于tony
# 4.再接着看,冒号后面是什么?是lambda匿名函数的返回值,返回值是dict.get(k),k现在是tony,所以它拿到的数据值就是tony对应的数据值100
# 5.接着循环产生新的数据值,一一进行比对就结束了,最终的返回结果是lisa
# 6.没有直接返回数字,这是因为虽然比对的时候是拿数字进行比对的,但是for循环拿出来的其实就是名字
# 如果匿名函数无法使用,则自定义一个函数,它的功能是传给其一个键,就会自动帮你在dic里去找对应的值,如果有就取出来,没有则返回None
def index(k):      # 这里只能写一个形参  因为for循环只能拿到字典的键
    return dic.get(k)
result = max(dic, key=index)
print(result)                            # lisa
# 之所以使用匿名函数,是因为它可以减少代码量,而且操作简洁
重要内置函数
# 内置函数之map()   用来做映射关系的
# l1 = [100, 200, 300, 400, 500, 600]
# 需求:将列表中所有的数据值自增200
# 使用map()函数
# result = map(lambda x: x + 200, l1)
# print(result)  # <map object at 0x000001954B581100>
# print(list(result))         # 把result转换成列表  [300,400,500,600,700,800]
# 上述操作的执行流程为:
# 1.map底层是for循环原理,它会依次循环出列表里的每一个数据值
# 2.每一次for循环出来的数据值,都会交给lambda匿名函数去处理
# 3.这个时候就相当于把数据值交给了lambda的形参x,然后返回x+200,即100+200,300
# 4.保存匿名函数返回的结果,并且一一对应,之后依次进行循环重复上述的步骤,就得到了最终的结果
# 如果匿名函数无法使用,则自定义一个函数,max会依次循环列表里的数据值,然后自动交给index传参执行,并且把返回的结果保留起来
# def index(a):
#     return a + 20
# result = map(index, l1)
# print(list(result))
# 内置函数之filter()   过滤
l1 = ['jason', 'kevin', 'oscar', 'tony']
# 需求:移除数据值里面的jason
# 使用filter()
# res = filter(lambda a: a != 'jason', l1)
# print(res)  # <filter object at 0x00000195F21E6C70>
# print(list(res))  # ['kevin', 'oscar', 'tony']
# 上述操作的执行流程为:
# 1.filter底层是for循环原理,它会依次循环出列表里的每一个数据值
# 2.每一次for循环出来的数据值,都会交给lambda匿名函数去处理
# 3.这个时候就相当于把数据值交给了lambda的形参a,形参a绑定了jason,然后看返回表达式为a不等于jason,那么jason就被丢弃了
# 4.之后依次进行循环重复上述的步骤,就得到了最终的结果
# 如果匿名函数无法使用,则自定义一个函数,filter会依次循环列表里的数据值,然后自动交给index传参执行,并过滤掉条件不成立的值
# def index(a):
#     return a != 'jason'
# res = filter(index, l1)
# print(list(res))
# 内置函数之reduce()  归纳总结
# l2 = [1, 2, 3]
# 需求:求列表中所有数据值的和
# 使用reduce()   将很多单体 变成一个整体
# from functools import reduce
# res = reduce(lambda x, y: x + y, l2)
# res = reduce(lambda x, y: x + y, l2)
# print(res)
# 上述操作的执行流程为:
# 1.当使用reduce操作一个列表时,如果lambda匿名函数后边是两个形参,就意味着要想触发lambda匿名函数,就需要两个实参
# 2.这个时候reduce它自己内部有一个机制,就是第一次取值的时候,它会取两个值,分别给到lambda匿名函数的形参x和y
# 3.这个时候返回值是x+y,它会被当做实参传给lambda匿名函数的形参,所以后面就会只取一个值
# 内置函数之zip()   拉链
# n1 = [1, 2, 3]
# n2 = ['jason', 'kevin', 'oscar']
# res = zip(n1, n2)
# print(res)  # <zip object at 0x000002A9E38C7F40>
# print(list(res))
# n1 = [1, 2, 3, 4]
# n2 = [5, 6, 7, 8]
# n3 = 'jack'
# res = zip(n1, n2, n3)
# print(list(res))
# n1 = [1, 2, 3, 4, 5, 6, 7]
# n2 = [5, 6, 7, 8]
# n3 = 'jason'
# res = zip(n1, n2, n3)
# print(list(res))

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号