Python基础(十四)
今日主要内容
- 装饰器扩展
- 有参装饰器
- 多个装饰器装饰一个函数
- 递归
一、装饰器扩展
(一)含有参数的装饰器
先来回顾一下装饰器的标准模式
def wrapper(fn):
def inner(*args, **kwargs):
"""扩展内容"""
ret = fn(*args, **kwargs)
"""扩展内容"""
return inner @wrapper
def func():
pass func()
回顾一下之前的游戏模拟,通过装饰器给我的游戏过程扩展了开挂的功能,装饰之后每次想玩游戏的时候调用函数都会给你先把挂打开,此时你的游戏函数已经被装饰了,但是现在有一个问题,我今天想自己玩一把,不想开挂了,怎么办?我们可以给装饰器传一个参数,来控制我的装饰器的开启和关闭就可以了
def wrapper_outer(argv): # 给装饰器加一个参数,控制装饰器开启关闭
def wrapper(fn):
def inner(hero):
if argv: # 如果是True执行添加装饰
print("开启外挂!")
ret = fn(hero)
print("关闭外挂!")
return ret
else: # 如果是False,执行原函数
ret = fn(hero)
return ret
return inner
return wrapper @wrapper_outer(True)
def play_lol(hero): # 基础函数参数
print("登陆游戏")
print("开始排位...")
print(f"选择英雄:{hero}")
print("游戏中...")
print("胜利!!!")
print("结束游戏")
return "坑比队友:xxx" # 基础函数返回值 print(play_lol("盖伦")) 运行结果:
开启外挂!
登陆游戏
开始排位...
选择英雄:盖伦
游戏中...
胜利!!!
结束游戏
关闭外挂!
坑比队友:xxx
刨析一下:
- 先来看装饰器和语法糖
@wrapper_outer(True)
先执行函数调用,函数调用返回的是我内层装饰器的函数名,相当于@wrapper
- 装饰器最外层的参数控制内层包装函数inner里面的函数部分是否执行,如果argv为真,相当于执行了包装,如果argv为假,执行原函数
- 通过给装饰器传参起到了控制装饰器是否生效的功能
def wrapper_outer(argv):
def wrapper(fn):
def inner(hero):
if argv: # 为真执行这里
print("开启外挂!")
ret = fn(hero)
print("关闭外挂!")
return ret
else: # 为假执行这里
ret = fn(hero)
return ret
return inner
return wrapper @wrapper_outer(True) # 先执行函数调用
- 注意:一旦给函数装饰过,装饰器的参数是不能变化的,因为闭包的原因参数已经被闭进去了,只能调用内层函数,无法再修改最外层的装饰器参数
flag = True
def wrapper_outer(argv):
def wrapper(fn):
def inner(*args, **kwargs):
if argv:
"""扩展功能"""
ret = fn(*args, **kwargs)
"""扩展功能"""
return ret
else:
ret = fn(*args, **kwargs)
return ret
return inner
return wrapper @wrapper_outer(flag)
def func():
pass flag = False
func() # 此时flag依然是True,装饰过就不能修改参数的值
- 先来看装饰器和语法糖
有参装饰器的标准模式
def wrapper_outer(argv):
def wrapper(fn):
def inner(*args, **kwargs):
if argv:
"""扩展功能"""
ret = fn(*args, **kwargs)
"""扩展功能"""
return ret
else:
ret = fn(*args, **kwargs)
return ret
return inner
return wrapper @wrapper_outer(True)
def func():
pass func()
(二)多个装饰器装饰一个函数
执行原理:从里到外进行包装
def wrapper1(fn):
def inner(*args, **kwargs):
print("扩展功能1")
ret = fn(*args, **kwargs)
print("扩展功能4")
return ret
return inner def wrapper2(fn):
def inner(*args, **kwargs):
print("扩展功能2")
ret = fn(*args, **kwargs)
print("扩展功能3")
return ret
return inner @wrapper1
@wrapper2
def func():
print("目标函数") func() 运行结果:
扩展功能1
扩展功能2
目标函数
扩展功能3
扩展功能4
刨析一下:
- 从里往外看,先用第一层装饰器
@wrapper2
装饰目标函数func()
,装饰完将其看作成一个整体,在被上层装饰器@wrapper1
装饰 - 返回值:执行完目标函数,将目标函数的返回值先反给最近的装饰器
@wrapper2
内部的inner包装函数中,之后再将@wrapper2
内部的inner包装函数的返回值返回给上一层装饰器@wrapper1
内部的inner中,最终得到的返回值是我调用函数的返回值 - 最终调用目标函数其实真正执行的是最外层装饰器中的包装函数
inner
,而最外层装饰器中的包装函数inner
包装着内层装饰器的包装函数inner
,而内层装饰器的包装函数inner
包装着真正的目表函数func
# 伪代码: def 装饰器1(传入目标函数):
def 内层包装函数1,也是真正执行的函数(目标函数的参数):
"""前扩展功能"""
目标函数(目标函数的参数)
"""后扩展功能"""
return 包装函数的函数名 def 装饰器2(传入目标函数):
def 内层包装函数2,也是真正执行的函数(目标函数的参数):
"""前扩展功能"""
目标函数(目标函数的参数)
"""后扩展功能"""
return 包装函数的函数名 @装饰器1
@装饰器2
def 目标函数(形参):
函数体 目标函数(实参) # 真正执行过程:
先执行:装饰器1的内层包装函数1,而传入的目标函数是:装饰器2的内层包装函数2
再执行:装饰器2的内层包装函数2,而传入的目标函数是:目标函数
- 从里往外看,先用第一层装饰器
二、递归
(一)什么是递归
- 首先递归是一个函数,只要满足两个要求的函数就是递归函数:
- 不断调用自己本身
- 有明确的结束条件
(二)递归深度
如果只是在不断的调用自己本身,没有一个明确的结束条件,那么就是一个死递归(无限循环)。
Python官方规定,为了避免无限制的调用自己本身,递归的最大深度为1000(最多只能调用自己本身1000次),实际递归深度为998
def func():
print(1)
func() func() 运行结果:
[Previous line repeated 994 more times]
1
1
1
...(共打印998个1)
可以通过导入sys模块,修改最大递归深度
import sys
sys.setrecursionlimit(100) # 修改递归深度 def func():
print(1)
func() func() 运行结果:
[Previous line repeated 94 more times]
1
1
1
...(实际打印98个1)
(三)递归的应用
求n的阶乘
def factorial(n):
if n == 1:
return 1
return factorial(n - 1) * n print(factorial(5)) 运行结果:
120
计算斐波那契序列
def fib(n):
if n <= 2:
return 1
return fib(n-1) + fib(n-2) print(list(map(fib,range(1, 6)))) 运行结果:
[1, 1, 2, 3, 5]
打印列表嵌套的每一个元素
l1 = [1, 2, [3, 4, [5, [6, 7, [8, 9], 10], 11, 12], 13], 14, 15] def func(lst):
for el in lst:
if type(el) == list:
func(el)
else:
print(el, end=" ") func(l1) 运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
给列表去重,不能使用集合
l1 = [1, 1, 2, 3, 4, 5, 6, 3, 3, 5, 6, 3, 4, 5] def del_repetition(lst):
for el in lst:
if lst.count(el) > 1:
lst.remove(el)
del_repetition(lst) del_repetition(l1)
print(l1) 运行结果:
[1, 2, 6, 3, 4, 5]
遍历文件夹中所有的文件
import os def read(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)
read(fi_d, n + 1) # 继续进行相同的操作
else:
print("\t" * n, fi) # 递归出口. 最终在这里隐含着return # 递归遍历目录下所有文件
read('../day16/', 0)
二分查找
# 普通递归版本⼆二分法
lst = [22, 33, 44, 55, 66, 77, 88, 99, 101, 238, 345, 456, 567, 678, 789]
n = 567
left = 0
right = len(lst) - 1 def binary_search(n, left, right):
if left <= right:
middle = (left + right) // 2
if n < lst[middle]:
right = middle - 1
elif n > lst[middle]:
left = middle + 1
else:
return middle
return binary_search(n, left, right)
# 这个return必须要加. 否则接收到的永远是None.
else:
return -1 print(binary_search(567, 0, len(lst) - 1))
三级菜单进入返回
menu = {
'北京': {
'海淀': {
'五道口': {
'soho': {},
'网易': {},
'google': {}
},
'中关村': {
'爱奇艺': {},
'汽车之家': {},
'youku': {},
},
'上地': {
'百度': {},
},
},
'昌平': {
'沙河': {
'北邮': {},
'北航': {},
},
'天通苑': {},
'回龙观': {},
},
'朝阳': {},
'东城': {},
},
'上海': {
'闵行': {
"人民广场": {
'炸鸡店': {}
}
},
'闸北': {
'火车战': {
'携程': {}
}
},
'浦东': {},
},
'天津': {
"和平": {
"小白楼": {},
"五大道小洋楼": {},
"滨江道": {},
},
"南开": {
"天大": {},
"南开": {},
"理工": {},
},
"河北": {
"天津之眼": {},
"海河": {},
"意式风情区": {},
"世纪钟": {},
"大悲院": {},
},
},
} def menu_func(menu):
while True:
for k in menu:
print(k)
key = input('input>>').strip()
if key == 'b' or key == 'q':
return key
elif menu.get(key):
ret = menu_func(menu[key])
if ret == 'q':
return 'q' menu_func(menu)
Python基础(十四)的更多相关文章
- python 基础(十四) 正则表达式
正则表达式 概念: 正则匹配就是一个模糊的匹配 只要符合我的匹配规则 就会认为是正确的数据(精确的匹配) 1.[] #代表原子表把想要匹配的内容写入原子表中 匹配包含的任意一位字符 [a] ...
- python基础十四之匿名函数
匿名函数 处理简单问题的简化函数,关键字lambda. # 格式:函数名 = lambda 参数:返回值 anonymity = lambda s: s ** 0.5 print(anonymity( ...
- Python 基础语法(四)
Python 基础语法(四) --------------------------------------------接 Python 基础语法(三)------------------------- ...
- 孤荷凌寒自学python第二十四天python类中隐藏的私有方法探秘
孤荷凌寒自学python第二十四天python类中隐藏的私有方法探秘 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 今天发现了python的类中隐藏着一些特殊的私有方法. 这些私有方法不管我 ...
- 孤荷凌寒自学python第十四天python代码的书写规范与条件语句及判断条件式
孤荷凌寒自学python第十四天python代码的书写规范与条件语句及判断条件式 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 在我学习过的所有语言中,对VB系的语言比较喜欢,而对C系和J系 ...
- Bootstrap<基础十四> 按钮下拉菜单
使用 Bootstrap class 向按钮添加下拉菜单.如需向按钮添加下拉菜单,只需要简单地在在一个 .btn-group 中放置按钮和下拉菜单即可.也可以使用 <span class=&qu ...
- 初学 Python(十四)——生成器
初学 Python(十四)--生成器 初学 Python,主要整理一些学习到的知识点,这次是生成器. # -*- coding:utf-8 -*- ''''' 生成式的作用: 减少内存占有,不用一次性 ...
- Python第二十四天 binascii模块
Python第二十四天 binascii模块 binascii用来进行进制和字符串之间的转换 import binascii s = 'abcde' h = binascii.b2a_hex(s) # ...
- Python第十四天 序列化 pickle模块 cPickle模块 JSON模块 API的两种格式
Python第十四天 序列化 pickle模块 cPickle模块 JSON模块 API的两种格式 目录 Pycharm使用技巧(转载) Python第一天 安装 shell 文件 Py ...
- Python进阶(十四)----空间角度研究类,类与类之间的关系
Python进阶(十四)----空间角度研究类,类与类之间的关系 一丶从空间角度研究类 对象操作对象属性 class A(): address = '沙河' def __init__(self, na ...
随机推荐
- Delphi - cxGrid连接Oracle数据库
cxGrid连接Oracle数据库 WinFrm窗体中需要添加OraSession .OraQuery和 OraDataSource控件. OraSession中配置数据库连接参数: OraQuery ...
- Python 基础(五)
pandas缺失值处理 import pandas as pd importrandom df01 = pd.DataFrame(np.random.randint(1,9),size = (4,4) ...
- 知识图谱推理与实践 (2) -- 基于jena实现规则推理
本章,介绍 基于jena的规则引擎实现推理,并通过两个例子介绍如何coding实现. 规则引擎概述 jena包含了一个通用的规则推理机,可以在RDFS和OWL推理机使用,也可以单独使用. 推理机支持在 ...
- 牛客暑假多校第二场 F trade
题意: 白兔有n个仓库,每个仓库有啊ai个货物,在每个仓库白兔可以装上任意数量的货物,也可以卸下任意数量的货物,现在有k个圆形信号阻隔器,然后有m个顾客下个一个订单,每个顾客的收货量有一个上限, 在每 ...
- Codeforces 898 B(拓展欧几里得)
Proper Nutrition 题意:有n元钱,有2种单价不同的商品,是否存在一种购买方式使得钱恰好花光,如果有输入任意一种方式,如果没有输出“NO” 题解:可以使用拓展欧几里得快速求解. #inc ...
- 【转 | 侵删】2D 绘图技术中的坐标系统与坐标变换
本文介绍在 2D 绘图技术中的坐标系统和坐标变换的相关知识.同时介绍 Kity 在这方面提供的 API .希望这些知识对于需要进行图形应用开发的同学会有所帮助. 锤子的故事 很久以前,有一个画家,他很 ...
- hdu 4081 Qin Shi Huang's National Road System(次小生成树prim)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4081 题意:有n个城市,秦始皇要修用n-1条路把它们连起来,要求从任一点出发,都可以到达其它的任意点. ...
- hdu2082 找单词 母函数模板
找单词 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...
- Node基础-CommonJS模块化规范
1.在本地项目中基于NPM/YARN安装第三方模块 第一步:在本地项目中创建一个"package.json"的文件 作用:把当前项目所有依赖的第三方模块信息(包含:模块名称以及版本 ...
- Django + Gunicorn + Nginx 部署之路
前言 最近,我已经成功将我的个人网站从 Flask 迁移到 Django 了,最早接触 Django 的时候大概是在 4 年前,我记得那个时候 Django 中的路由配置使用 正则 来进行的,但是我有 ...