热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

py多层装饰器与算法的学习day14

昨日学习回顾闭包函数需要满足两个条件:条件1:定义在函数体内部的函数条件2:内部函数使用了外部函数名称空间中的名字作用:函数体代码得到外界的数据可以直接通过形参

昨日学习回顾

闭包函数

需要满足两个条件:
条件1:定义在函数体内部的函数
条件2:内部函数使用了外部函数名称空间中的名字
作用:
函数体代码得到外界的数据可以直接通过形参
而闭包是给函数体代码传参的第二种方式

'''
方式1
直接通过当前函数的形参
def index(name):
print(name)
方式2
通过闭包函数的形式包给内部函数
def outer(name):
# name = 'jason'
def index():
print(name)
return index
'''

装饰器的内容

装饰器
定义:
在不改变被装饰对象的'原代码'及'调用方式'的情况下增加新的功能
# 记录一个装饰器模板
def outer(func_name): # 接收被装饰对象的名字
def inner(*arg, **kwargs): # 兼容所有的函数类型
# 执行被装饰函数之前可以做的额外操作
res = func_name(*args, **kwargs)
# 执行被装饰函数之前可以做的额外操作
return res # 返回真正函数的返回值
return inner
装饰器语法糖
定义:
就是@+函数名
@outer
def index():
pass
'''
@outer的本质其实就是 inder = outer(index)
'''
右侧的index是真正的函数名
左侧的index是变量名
装饰器修复技术
# 查看函数的注释
help()
# 修复技术的主要功能就是以假乱真
from functools import warps
def outer(func_name): # 接收被装饰对象名字
@warp(func_name) # 固定搭配
def inner(*args, **kwargs)
res = func_name(*args, **kwargs)
return res
return inner

今日学习内容

多层装饰器

语法糖定义:
语法糖会将紧挨着的被装饰对象的名字当做参数自动传入装饰器函数中
def outter1(func1):
print('加载了outter1')
def wrapper1(*args, **kwargs):
print('执行了wrapper1')
res1 = func1(*args, **kwargs)
return res1
return wrapper1
def outter2(func2):
print('加载了outter2')
def wrapper2(*args, **kwargs):
print('执行了wrapper2')
res2 = func2(*args, **kwargs)
return res2
return wrapper2
def outter3(func3):
print('加载了outter3')
def wrapper3(*args, **kwargs):
print('执行了wrapper3')
res3 = func3(*args, **kwargs)
return res3
return wrapper3
@outter1
@outter2
@outter3
def index():
print('from index')

运行结果:
执行了wrapper3
执行了wrapper2
执行了wrapper1
# 得出结论
多层装饰器的装饰顺序是越靠近被装饰函数的越先调用

1

有参装饰器

# 有参函数的模板
def 有参装饰器(x,y,z):
def outter(func):
def wrapper(*args, **kwargs):
res = func(*args, **kwargs)
return res
return wrapper
return outter
@有参装饰器(1,y=2,z=3)
def 被装饰对象():
pass
# 课堂内容
def outer(source_data):
def login_auth(func_name): # 不能动 只能接收一个被装饰对象名字
def inner(*args, **kwargs): # 不能动 是专门用来给被装饰的对象传参的
username = input('username>>>:').strip()
password = input('password>>>:').strip()
# 校验用户数据 数据的来源可以有很多 比如全局字典 全局列表 文本文件 数据库
# 数据的来源不同 处理方式就不同 对应的代码编写就不一样
# 分支结构处理 然后根据不同的参数提示 匹配不同的流程
if source_data == '1':
print('使用字典的方式处理数据')
elif source_data == '2':
print('使用列表的方式处理数据')
elif source_data == '3':
print('使用文件操作处理数据')
else:
print('其他操作情况')
res = func_name(*args, **kwargs)
return res
return inner
return login_auth
@outer('3')
def index():
print('from index')
index()
# 结果
username>>>:123
password>>>:123
使用文件操作处理数据
from index
"""
函数名加括号 执行优先级最高
@outer('3')
左侧是语法糖结构 右侧是函数名加括号结构
先执行函数调用 outer('3') 返回值是login_auth
在执行语法糖结构 @login_auth
发现最后还是一个普通的装饰器
有参装饰器目的仅仅是给装饰器传递额外的参数
装饰器最多就三层嵌套
from functools import wraps
@wraps(func_name)
"""

递归函数

# 概念:
在函数内部,可以调用其他函数,如果一个函数在内部调用自身本身,这个函数就是递归函数

# 直接调用自己
def index():
print('from index')
index()
index()
这样子运行就会超出最大递归深度,但是好在pycharm中有应急机制
# 间接调用自己
def index():
print('from index')
func()
def func():
print('from func')
index()
func()
'''
在递归深度的状态下是有个最大值的,一般是997或998
1000是官方给出的数据
'''
import sys
print(sys.getrecursionlimit()) # 获取默认的最大递归深度
sys.setrecursionlimit(2000) # 还可以修改最大递归深度
'但是真正的递归是要满足条件的'
1.每次递归,复杂度必须比上次降低
2.必须要有明确的结束条件
# 课堂上举的例子
需求:我想知道我们班坐在第一排的某个学生年龄
过程:
我问他多大了 他调皮不告诉我 说比后面那个同学大两岁
后面的说比他后面的大两岁
...
问到最后你一排 终于开口说 18岁
...
知道最后一排的年级回推就可以知道第一排的年级
名词:
递推:一层层往下问
回溯:根据结果推结论
'''
# 如何编写代码完成
# 目标人物的年龄 = 后一排年龄 + 2
# 后一排年龄 = 后后一排年龄 + 2
# 后后一排年龄 = 后后后一排年龄 + 2
# 后后后后一排年龄 = 18
# 将求问年龄变成函数
# 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(4))
'''
# 另外的小例子:
计算1-100之间相加的和
按照我们之前学过的内容,可以考虑用循环做这个问题
def sum_1(n):
sum = 0
for i in range(1, n+1):
sum += i
print(sum)
sun_1(100) # 5050
然后接下来我们用递归的思路推导一下这个题
def sun_2(n):
if n > 0:
return n + sum_2(n-1)
else:
return 0
sum = sum_2(100)
print(sum) # 5050
递归函数的优点是定义简单,逻辑清晰。
理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰,所以循环也可以看成是一种特殊的递归

递归练习

l1 = [1,[2,[3,[4,[5,[6,[7,[8,[9,]]]]]]]]]
'''需求:循环打印出列表中每一个数字'''
# 写代码之前一定要先理清思路
"""
完整步骤
1.for循环大列表
2.判断元素是否是数字 如果是则打印
3.如果不是则for循环
4.判断元素是否是数字 如果是则打印
5.如果不是则for循环
6.判断元素是否是数字 如果是则打印
7.如果不是则for循环
ps:重复做一些事情 但是每次都比上一次简单一些 >>>: 递归函数
"""
def get_num(l):
for i in l:
if isinstance(i,int): # 判断某个数据是否属于某个类型
print(i)
else:
get_num(i)
get_num(l1)
'''
1
2
3
4
5
6
7
8
9
'''

算法之二分法

算法的概念:
能够对一定规范的输入,在有限时间内获得所要求的输出
大白话:
算法其实就是解决问题的有效方法

今天上课学的一个入门算法叫'二分法'
'二分法使用有前提: 数据集必须有先后顺序(升序 降序)'
# 原理
二分法原理
获取数据集中间的元素 比对大小
如果中间的元素大于目标数据 那么保留数据集的左边一半
如果中间的元素小于目标数据 那么保留数据集的右边一半
然后针对剩下的数据集再二分
如果中间的元素大于目标数据 那么保留数据集的左边一半
如果中间的元素小于目标数据 那么保留数据集的右边一半
...

例子:
l1 = [13,21,35,46,52,67,76,87,99,123,213,321,432,564]
def get_target(l1,target_num):
# 最后需要考虑找不到的情况 l1不可能无限制二分
if len(l1) == 0:
print('不好意思 真的没有 找不到')
return
# 1.获取中间元素的索引值(只能是整数)
middle_index = len(l1) // 2
# 2.判断中间索引对应的数据与目标数据的大小
if target_num > l1[middle_index]:
# 3.保留数据集右侧
l1_left = l1[middle_index+1:]
# 3.1.对右侧继续二分 重复执行相同代码 并且复杂度降低
print(l1_left)
get_target(l1_left,target_num)
elif target_num # 4.保留数据集左侧
l1_right = l1[:middle_index]
print(l1_right)
# 4.1.对右侧继续二分 重复执行相同代码 并且复杂度降低
get_target(l1_right,target_num)
else:
print('找到了',target_num)
# get_target(l1,432)
# get_target(l1,22)
get_target(l1,13)

算法拓展

冒泡排序
# 概念
"简单来说就是将一个无序的列表,从第一个元素开始与第一个元素后面的一个元素比较,大于后面的元素就交换位置,小于后面的元素就在用后面的那一个元素与下下一个元素相比"
"直到最后一个元素算是排完一轮这个过程就是是泡泡往上冒一样,故称为冒泡算法"
# 举个小例子
def bubbleSort(arr):
n = len(arr)
# 遍历所有数组元素
for i in range(n):
# Last i elements are already in place
for j in range(0, n-i-1):
if arr[j] > arr[j+1] :
arr[j], arr[j+1] = arr[j+1], arr[j]
arr = [64, 34, 25, 12, 22, 11, 90]
bubbleSort(arr)
print ("排序后的数组:")
for i in range(len(arr)):
print ("%d" %arr[i])
结果:
'''
11
12
22
25
34
64
90
'''
选择排序
# 概念
'首先在所给的未排序序列中找到最小(大)的元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的后面。以此类推,直到所有元素均排序完毕。'
'先找小的元素就是顺序排序,先找大的就是逆序排序'
# 举个小例子
A = [64, 25, 12, 22, 11] # 定义一个列表
def get_min(): # 定义一个函数
for i in range(len(A)): # for循环A列表中的元素
min_idx = i # 定义一个变量名用于接收最小元素的值
for j in range(i+1, len(A)): # 再一个for循环A列表中剩余的元素值
if A[min_idx] > A[j]: # 对之前接收的最小值与之后面的一个数进行比对
min_idx = j # 接收相比较下更小元素的值
A[i], A[min_idx] = A[min_idx], A[i]
print ("排序后的数组:")
for i in range(len(A)):
print("%d" %A[i])
get_min()
结果:
'''
排序后的数组:
11
12
22
25
64
'''
排序引入、插入排序、快速排序、希尔排序···

今天学习了算法,就学了一个递归算法,还有好多种其他的算法,还是比较有趣的



推荐阅读
  • 本文整理了315道Python基础题目及答案,帮助读者检验学习成果。文章介绍了学习Python的途径、Python与其他编程语言的对比、解释型和编译型编程语言的简述、Python解释器的种类和特点、位和字节的关系、以及至少5个PEP8规范。对于想要检验自己学习成果的读者,这些题目将是一个不错的选择。请注意,答案在视频中,本文不提供答案。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 本文由编程笔记小编整理,主要介绍了使用Junit和黄瓜进行自动化测试中步骤缺失的问题。文章首先介绍了使用cucumber和Junit创建Runner类的代码,然后详细说明了黄瓜功能中的步骤和Steps类的实现。本文对于需要使用Junit和黄瓜进行自动化测试的开发者具有一定的参考价值。摘要长度:187字。 ... [详细]
  • 本文分析了Wince程序内存和存储内存的分布及作用。Wince内存包括系统内存、对象存储和程序内存,其中系统内存占用了一部分SDRAM,而剩下的30M为程序内存和存储内存。对象存储是嵌入式wince操作系统中的一个新概念,常用于消费电子设备中。此外,文章还介绍了主电源和后备电池在操作系统中的作用。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • PHP中的单例模式与静态变量的区别及使用方法
    本文介绍了PHP中的单例模式与静态变量的区别及使用方法。在PHP中,静态变量的存活周期仅仅是每次PHP的会话周期,与Java、C++不同。静态变量在PHP中的作用域仅限于当前文件内,在函数或类中可以传递变量。本文还通过示例代码解释了静态变量在函数和类中的使用方法,并说明了静态变量的生命周期与结构体的生命周期相关联。同时,本文还介绍了静态变量在类中的使用方法,并通过示例代码展示了如何在类中使用静态变量。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • Day2列表、字典、集合操作详解
    本文详细介绍了列表、字典、集合的操作方法,包括定义列表、访问列表元素、字符串操作、字典操作、集合操作、文件操作、字符编码与转码等内容。内容详实,适合初学者参考。 ... [详细]
  • 本文介绍了在iOS开发中使用UITextField实现字符限制的方法,包括利用代理方法和使用BNTextField-Limit库的实现策略。通过这些方法,开发者可以方便地限制UITextField的字符个数和输入规则。 ... [详细]
  • Linux的uucico命令使用方法及工作模式介绍
    本文介绍了Linux的uucico命令的使用方法和工作模式,包括主动模式和附属模式。uucico是用来处理uucp或uux送到队列的文件传输工具,具有操作简单快捷、实用性强的特点。文章还介绍了uucico命令的参数及其说明,包括-c或--quiet、-C或--ifwork、-D或--nodetach、-e或--loop、-f或--force、-i或--stdin、-I--config、-l或--prompt等。通过本文的学习,读者可以更好地掌握Linux的uucico命令的使用方法。 ... [详细]
  • EzPP 0.2发布,新增YAML布局渲染功能
    EzPP发布了0.2.1版本,新增了YAML布局渲染功能,可以将YAML文件渲染为图片,并且可以复用YAML作为模版,通过传递不同参数生成不同的图片。这个功能可以用于绘制Logo、封面或其他图片,让用户不需要安装或卸载Photoshop。文章还提供了一个入门例子,介绍了使用ezpp的基本渲染方法,以及如何使用canvas、text类元素、自定义字体等。 ... [详细]
  • 本文介绍了RxJava在Android开发中的广泛应用以及其在事件总线(Event Bus)实现中的使用方法。RxJava是一种基于观察者模式的异步java库,可以提高开发效率、降低维护成本。通过RxJava,开发者可以实现事件的异步处理和链式操作。对于已经具备RxJava基础的开发者来说,本文将详细介绍如何利用RxJava实现事件总线,并提供了使用建议。 ... [详细]
  • EPPlus绘制刻度线的方法及示例代码
    本文介绍了使用EPPlus绘制刻度线的方法,并提供了示例代码。通过ExcelPackage类和List对象,可以实现在Excel中绘制刻度线的功能。具体的方法和示例代码在文章中进行了详细的介绍和演示。 ... [详细]
  • PHP反射API的功能和用途详解
    本文详细介绍了PHP反射API的功能和用途,包括动态获取信息和调用对象方法的功能,以及自动加载插件、生成文档、扩充PHP语言等用途。通过反射API,可以获取类的元数据,创建类的实例,调用方法,传递参数,动态调用类的静态方法等。PHP反射API是一种内建的OOP技术扩展,通过使用Reflection、ReflectionClass和ReflectionMethod等类,可以帮助我们分析其他类、接口、方法、属性和扩展。 ... [详细]
author-avatar
祥荣华贵
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有