今日主要内容

  • 装饰器扩展

    • 有参装饰器
    • 多个装饰器装饰一个函数
  • 递归

一、装饰器扩展

(一)含有参数的装饰器

  • 先来回顾一下装饰器的标准模式

    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)

(三)递归的应用

  1. 求n的阶乘

    def factorial(n):
    if n == 1:
    return 1
    return factorial(n - 1) * n print(factorial(5)) 运行结果:
    120
  2. 计算斐波那契序列

    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]
  3. 打印列表嵌套的每一个元素

    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
  4. 给列表去重,不能使用集合

    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]
  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)
  6. 二分查找

    # 普通递归版本⼆二分法
    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))
  7. 三级菜单进入返回

    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基础(十四)的更多相关文章

  1. python 基础(十四) 正则表达式

    正则表达式 概念: 正则匹配就是一个模糊的匹配 只要符合我的匹配规则 就会认为是正确的数据(精确的匹配) 1.[] #代表原子表把想要匹配的内容写入原子表中   匹配包含的任意一位字符 [a]     ...

  2. python基础十四之匿名函数

    匿名函数 处理简单问题的简化函数,关键字lambda. # 格式:函数名 = lambda 参数:返回值 anonymity = lambda s: s ** 0.5 print(anonymity( ...

  3. Python 基础语法(四)

    Python 基础语法(四) --------------------------------------------接 Python 基础语法(三)------------------------- ...

  4. 孤荷凌寒自学python第二十四天python类中隐藏的私有方法探秘

    孤荷凌寒自学python第二十四天python类中隐藏的私有方法探秘 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 今天发现了python的类中隐藏着一些特殊的私有方法. 这些私有方法不管我 ...

  5. 孤荷凌寒自学python第十四天python代码的书写规范与条件语句及判断条件式

    孤荷凌寒自学python第十四天python代码的书写规范与条件语句及判断条件式 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 在我学习过的所有语言中,对VB系的语言比较喜欢,而对C系和J系 ...

  6. Bootstrap<基础十四> 按钮下拉菜单

    使用 Bootstrap class 向按钮添加下拉菜单.如需向按钮添加下拉菜单,只需要简单地在在一个 .btn-group 中放置按钮和下拉菜单即可.也可以使用 <span class=&qu ...

  7. 初学 Python(十四)——生成器

    初学 Python(十四)--生成器 初学 Python,主要整理一些学习到的知识点,这次是生成器. # -*- coding:utf-8 -*- ''''' 生成式的作用: 减少内存占有,不用一次性 ...

  8. Python第二十四天 binascii模块

    Python第二十四天 binascii模块 binascii用来进行进制和字符串之间的转换 import binascii s = 'abcde' h = binascii.b2a_hex(s) # ...

  9. Python第十四天 序列化 pickle模块 cPickle模块 JSON模块 API的两种格式

    Python第十四天 序列化  pickle模块  cPickle模块  JSON模块  API的两种格式 目录 Pycharm使用技巧(转载) Python第一天  安装  shell  文件 Py ...

  10. Python进阶(十四)----空间角度研究类,类与类之间的关系

    Python进阶(十四)----空间角度研究类,类与类之间的关系 一丶从空间角度研究类 对象操作对象属性 class A(): address = '沙河' def __init__(self, na ...

随机推荐

  1. Delphi - cxGrid连接Oracle数据库

    cxGrid连接Oracle数据库 WinFrm窗体中需要添加OraSession .OraQuery和 OraDataSource控件. OraSession中配置数据库连接参数: OraQuery ...

  2. Python 基础(五)

    pandas缺失值处理 import pandas as pd importrandom df01 = pd.DataFrame(np.random.randint(1,9),size = (4,4) ...

  3. 知识图谱推理与实践 (2) -- 基于jena实现规则推理

    本章,介绍 基于jena的规则引擎实现推理,并通过两个例子介绍如何coding实现. 规则引擎概述 jena包含了一个通用的规则推理机,可以在RDFS和OWL推理机使用,也可以单独使用. 推理机支持在 ...

  4. 牛客暑假多校第二场 F trade

    题意: 白兔有n个仓库,每个仓库有啊ai个货物,在每个仓库白兔可以装上任意数量的货物,也可以卸下任意数量的货物,现在有k个圆形信号阻隔器,然后有m个顾客下个一个订单,每个顾客的收货量有一个上限, 在每 ...

  5. Codeforces 898 B(拓展欧几里得)

    Proper Nutrition 题意:有n元钱,有2种单价不同的商品,是否存在一种购买方式使得钱恰好花光,如果有输入任意一种方式,如果没有输出“NO” 题解:可以使用拓展欧几里得快速求解. #inc ...

  6. 【转 | 侵删】2D 绘图技术中的坐标系统与坐标变换

    本文介绍在 2D 绘图技术中的坐标系统和坐标变换的相关知识.同时介绍 Kity 在这方面提供的 API .希望这些知识对于需要进行图形应用开发的同学会有所帮助. 锤子的故事 很久以前,有一个画家,他很 ...

  7. hdu 4081 Qin Shi Huang's National Road System(次小生成树prim)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4081 题意:有n个城市,秦始皇要修用n-1条路把它们连起来,要求从任一点出发,都可以到达其它的任意点. ...

  8. hdu2082 找单词 母函数模板

    找单词 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  9. Node基础-CommonJS模块化规范

    1.在本地项目中基于NPM/YARN安装第三方模块 第一步:在本地项目中创建一个"package.json"的文件 作用:把当前项目所有依赖的第三方模块信息(包含:模块名称以及版本 ...

  10. Django + Gunicorn + Nginx 部署之路

    前言 最近,我已经成功将我的个人网站从 Flask 迁移到 Django 了,最早接触 Django 的时候大概是在 4 年前,我记得那个时候 Django 中的路由配置使用 正则 来进行的,但是我有 ...