【python基础】第21回 周总结

目录

1. 名称空间与作用域

2. 装饰器

3. 递归函数

4. 二分法(算法)

5. 三元表达式

6. 匿名函数

7. 内置函数

详解

1. 名称空间与作用域

1.1 什么是名称空间

就是用来存放变量名与数据值之间绑定关系的地方

1.2 名称空间分类

1. 内置名称空间

解释器运行(创建)  解释器关闭(销毁),python解释器运行就会立刻创建的空间,写代码过程中可以直接使用的名字都在该空间中,eg:len() print() input() ...

2. 全局名称空间

py文件运行(创建)  py文件结束(销毁),py文件运行代码过程中产生的名字都会存入该空间,普通代码,分支结构里面的变量名等

3. 局部名称空间

函数体代码运行(创建)  函数体代码结束(销毁),函数体代码运行过程中产生的名字都会存入该空间

4. 查找顺序

当前在全局名称空间,先全局名称空间 后内置名称空间

当前在局部名称空间,局部名称空间  >>>:  全局名称空间  >>>: 内置名称空间

名字的查找顺序默认情况下不能颠倒只能是 局部>>>:全局>>>:内置

1.3 名称空间作用域

1. 内置名称空间:在程序任意位置都可以使用(全局有效)

2. 全局名称空间:在程序任意位置都可以使用(全局有效)

3. 局部名称空间:在各自的局部空间可以使用(局部有效)

1.4 global 与 nonlocal

正常情况下 局部名称空间里面出现新的名字会在局部名称空间中存储,但是有时候需要在局部名称空间中修改全局名称空间的名字

1. 局部修改全局名称空间中不可变类型的数据 需要使用关键字global声明,如果是可变类型 则无需关键字声明

2. nonlocal 在内存局部名称空间修改外层局部名称空间中的不可变类型

1.5 函数名的多种使用方式

1. 函数名也可以被用来多次赋值(函数名与变量名使用一致)
2. 函数名还可以当做函数的实参
3. 函数名还可以当做函数的返回值
4. 函数名还可以当做容器类型里面的数据值

2. 函数 装饰器

2.1 闭包函数

1. 闭包函数定义

.定义在函数内部的函数,内部函数使用了外部函数名称空间中的名字,只有符合上述两个特征的函数才能称之为闭包函数

2. 闭包函数实际应用

给函数体代码传值的  方式1:通过形参  ,方式2:闭包函数

2.2 装饰器

1. 装饰器本质原则

本质:在不改变被装饰对象原来的'调用方式'和'内部代码'的情况下给被装饰对象添加新的功能,

原则:对修改封闭 对扩展开放

2. 知识储备

help函数可用于查找模块,功能,类,关键字等的文档

复制代码
print(time.time())  # 1656987566.7260265
'''时间戳(秒数):当前距离1970年1月1日0时0分0秒所经历的秒数'''
实际应用>>>:统计代码的运行时间
start_time = time.time()  #  100
for i in range(100000):
     print(i)
end_time = time.time()
print('for循环的执行时间是:%s'%(end_time - start_time))
    time.sleep(3)
'''让程序原地等待三秒'''
 print('停三秒')
复制代码

2.3 装饰器模板

1. 模板

复制代码
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
复制代码

2. 语法糖

@outer  # index = outer(index)
def index():
    pass

2.4 多层装饰器

1. 什么是多层装饰器

多层装饰器是从下往上依次执行,需要注意的是,被装饰的函数名所指代的函数是一直被装饰器中的内层函数所取代。

2. 语法糖的功能

会自动将下面紧挨着的函数名当做参数传递给@符号2后面的函数名(加括号调用)

3.代码讲解

复制代码
def outter1(func1):  # 13.func1 = wrapper2函数名
    print('加载了outter1')  # 14.第三个打印
    def wrapper1(*args, **kwargs):
        print('执行了wrapper1')
        res1 = func1(*args, **kwargs)
        return res1
    return wrapper1  # 15.返回wrapper1

def outter2(func2):  # 9.func2 = wrapper3函数名
    print('加载了outter2') # 10.第二个打印
    def wrapper2(*args, **kwargs):
        print('执行了wrapper2')
        res2 = func2(*args, **kwargs)
        return res2
    return wrapper2  # 11.返回wrapper2

def outter3(func3):  # 4.func3 = 真正的index函数
    print('加载了outter3')  # 5.第一个打印
    def wrapper3(*args, **kwargs):
        print('执行了wrapper3')
        res3 = func3(*args, **kwargs)
        return res3
    return wrapper3  # 6.返回wrapper3


@outter1  # 12.index = outter1(wrapper2)  调用outter1 把 outter2参数传进去 上面没有语法糖 最后用被装饰的函数一样的名字接受函数
@outter2  # 8.wrapper2 = outter2(wrapper3) 调用outter2 把 outter3参数传进去
@outter3  # 7.wrapper3 = outter3(真正的index函数名)  传给@outter2
# 1.如果上面没有其他语法糖了同名的函数名赋值一下index = = outter3(把真正的index函数名传进去),
# 2.如果语法糖叠加在一起的话,只有到最后一步才会使用和真正装饰的和函数名一样的名字去赋值,如果不到最后一步)
# 3.函数名加括号执行优先级最高 先执行outter3
def index():
    print('from index')
index()
# 多层语法糖解读顺序是先看语法糖有几个,然后再由下往上去看,遇到最后一个才会使用相同的变量名传给装饰器函数使用
# 语法糖三:wrapper3 = outter3(index),加载了outter3
# 语法糖二:wrapper2 = outter2(wrapper3),加载了outter2
# 语法糖一;index = outter1(wrapper2),加载了outter1
# 执行顺序就是:wrapper1>>>>>wrapper2>>>>>wrapper3
# 加载outer3>>>加载outer2>>>加载outer1>>>index()>>>运行wrapper1函数体代码>>>然后再执行outer2函数体代码>>>然后再执行wrapper3的函数体代码
复制代码

2.5 有参装饰器

1. 什么是有参装饰器

是为装饰器提供多样功能选择的实现提供的,实现原理是三层闭包

2. 代码讲解

初始代码

复制代码
def login_auth(func_name):
    def inner(*args, **kwargs):
        username = input('username>>>:').strip()
        password = input('password>>>:').strip()
        if username == 'jason' and password == '123':
            res = func_name(*args, **kwargs)
            return res
        else:
            print('用户权限不够 无法调用函数')
    return inner
复制代码

有参装饰,在装饰器内部可以切换多种数据来源 ,如 列表 ,字典 ,文档

复制代码
def outer(condition,type_user):
    def login_auth(func_name):  # 这里不能再填写其他形参
        def inner(*args, **kwargs):  # 这里不能再填写非被装饰对象所需的参数
            username = input('username>>>:').strip()
            password = input('password>>>:').strip()
            # 应该根据用户的需求执行不同的代码
            if type_user =='jason':print('VIP')
            if condition == '列表':
                print('使用列表作为数据来源 比对用户数据')
            elif condition == '字典':
                print('使用字典作为数据来源 比对用户数据')
            elif condition == '文件':
                print('使用文件作为数据来源 比对用户数据')
            else:
                print('去你妹的 我目前只有上面几种方式')
        return inner
    return login_auth
@outer('列表','jason')
def index():
    print('from index')
index()
复制代码

3. 递归函数

3.1 什么是递归函数

编程语言中,函数直接或间接调用函数本身,则该函数称为递归函数。

3.2 递归函数

1. 递归调用:直接调用

def index():
    print('from index')
    index()
index()

2. 递归调用:间接调用

def index():
    print('from index')
    func()
def func():
    print('from func')
    index()
func()

3. python中允许函数最大递归调用的次数,官方给出的限制是1000 用代码去验证可能会有些许偏差(997 998...)

复制代码
# count = 1
# def index():
#     print('from index')
#     global count
#     count += 1  # count = count + 1
#     print(count)
#     index()
# index()
# import sys
# print(sys.getrecursionlimit())  # 1000  获取递归最大次数
sys.setrecursionlimit(2000)  # 自定义最大次数
print(sys.getrecursionlimit())
复制代码

4. 递归函数真正的应用场景

递推:一层层往下寻找答案

回溯:根据已知条件推导最终结果

每次调用的时候都必须要比上一次简单,并且递归函数最终都必须要有一个明确的结束条件

4. 二分法(算法)

4.1 什么是算法  算法就是解决问题的方法

       算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。如果一个算法有缺陷,或不适合于某个问题,执行这个算法将不会解决这个问题。不同的算法可能用不同的时间,空间或效率来完成同样的任务。一个算法的优劣可以用空间复杂度与时间复杂度来衡量。

       二分法 快拍 插入 堆排 链表 双向链表 约瑟夫问题

4.2 二分法

1. 二分法是所有算法里面最简单的算法,是一种非常高效的算法,它常常用于计算机的查找过程中

复制代码
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)
复制代码

2. 二分法的缺陷

数据集必须是有序的

查找的数如果在开头或者结尾 那么二分法效率更低(for 循环)

4.3 其他算法

1. 快排

快排 全名 快速排序算法
快速排序(QuickSort)是对冒泡排序的一种改进。快速排序由C. A. R. Hoare在1962年提出。

它的基本思想是:
1. 从要排序的数据中取一个数为“基准数”。
2. 通过一趟排序将要排序的数据分割成独立的两部分,其中左边的数据都比“基准数”小,右边的数据都比“基准数”大。
3. 然后再按步骤2对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
该思想可以概括为:挖坑填数 + 分治法。分治法(分而治之)

2. 插入

插入算法是一种排序算法

在运用插入算法时一般将数据分为两组,有序组和无序组,并且将数据的第一个元素默认为有序组,将无序组的元素一个一个按照某种排列方式插入到有序组中。

3. 冒泡

冒泡算法是一种经典的排序算法,冒泡,顾名思义就是轻(小)的往上冒,重(大)的往下沉,也称鸡尾酒算法

解析首先我们需要确立两层嵌套for循环,第一层for循环主要控制总体循环的趟数,第二层for循环主要是比对相邻的两个数,运用CAS(比较并替换)的思路将每一趟的第二层for循环执行完成

5. 三元表达式

5.1 语法结构

数据值1  if  条件  else  数据值3

1. 如果if 后面的条件成立 则使用if前面的值

2. 如果if 后面的条件不成立 则使用else后面的值

3. 三元表达式:仅限于二选一的情况并且不建议嵌套使用,三元表达式一般情况下两个值都是具体的数据值不是函数

4.在python中代码不是精简的越少越好 在精简的过程中还要保证代码的可读性

5.2 各种表达式

1. 列表生成式   变量名相关处理 for 变量名 in 数据集

列表生成式中只能出现for和if,用列表生成式 一行代码解决,先执行for 循环 然后将一个个的数据值交给for循环前面处理,对列表数据值统一处理

还支持if判断   先执行for循环 然后将一个个的数据值交给if判断 结果为True则最后交给for循环前面处理

2. 字典生成式  {k:v for 变量名 in 数据集}

3. 集合生成式  变量名 for 变量名 in 数据集 if 条件

6. 匿名函数

6.1 定义

匿名函数就是没有函数名的函数,一种使用lambda定义的匿名函数。这种函数可以用在任何普通函数可以使用的地方,但在定义时被严格限定为单一表达式。从语义上讲,它只是普通函数的语法糖

6.2 语法结构

lambda 形参:返回值

6.3 具体案例

(lambda x: x + 1)(123) # 直接调用
res = lambda x: x + 1  # 命名调用
print(res(123))

6.4 应用场景

匿名函数通常都需要配合其他函数一起使用 用于减少代码

7. 内置函数

7.1 max() 求最大值  min() 求最小值

l1 = [223, 3423, 123, 24, 34, 35, 435, 3, 24, 3534, 53, 24, 234, 132, 4234, 456, 456, 5345, 4, 234, 345, 23, 2123432]
res = max(l1)
print(res)  # 2123432

7.2 map() 映射

l1 = [11, 22, 33, 44, 55, 66]
# 需求:将列表中所有的数据值自增20
res = map(lambda x: x + 20, l1)
print(res)  # <map object at 0x000001E5F99B0130>
print(list(res))

7.3 filter() 过滤

l1 = ['jason', 'kevin', 'oscar', 'tony']
# 需求:移除数据值里面的jason
res = filter(lambda a: a != 'jason', l1)
print(res)  # <filter object at 0x00000195F21E6C70>
print(list(res))  # ['kevin', 'oscar', 'tony'] 需要定义

7.4 reduce() 累加和

l2 = [1, 2, 3]
# 需求:求列表中所有数据值的和
from functools import reduce
res = reduce(lambda x, y: x + y, l2)
print(res)  # 6

7.5 zip() 拉链(连接)

# 结合成小元组
n1 = [1, 2, 3]
n2 = ['jason', 'kevin', 'oscar']
res = zip(n1, n2)
print(res)  # <zip object at 0x000002A9E38C7F40>
print(list(res)) # [(1, 'jason'), (2, 'kevin'), (3, 'oscar')]
# 一一对应 ,不一一对应 返回最小的个数
posted @   |相得益张|  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示