Python(装饰器,递归函数)

一、开放封闭原则

​ 软件面世时,不可能把所有的功能都设计好,再未来的一两年功能会陆续上线,定期更新迭代,软件之前所用的源代码,函数里面的代码以及函数的调用方式一般不会修改,可以在源码不改变的情况下,增加一些新的功能.

  1. 开放原则 : 在源码尽量不改变的情况下,更新增加一些额外的功能.
  2. 封闭原则 : 不要改变源码和调用方式

二、初识装饰器

​ 装饰器是以功能为导向的,就是一个函数,在不改变原被装饰的函数的源代码以及调用方式下,为其添加额外的功能.

  1. python中装饰器 : 完美的诠释开放封闭原则

  2. 装饰器就是一个函数 : 他要装饰一个函数,在不改变原函数的源码以及调用方式的前提下,给其增加一个额外的功能

    import time
    def index():
    time.sleep(2) # 模拟一下网络延迟以及代码的效率
    print('欢迎访问博客园主页')
    def home(name):
    time.sleep(3) # 模拟一下网络延迟以及代码的效率
    print(f'欢迎访问{name}主页')
    def timer(func): # func = index
    def inner():
    start_time = time.time()
    func()
    end_time = time.time()
    print(f'此函数的执行效率为{end_time-start_time}')
    return inner
    index = timer(index)
    index()
    # 此为装饰器的雏形,虽然满足了开放封闭原则,但是如果当源代码又返回值时则此代码不够完善.

三、被装饰函数带返回值

​ 当需要与原代码返回值一致的时候需要注意一下两点

  1. 明确源代码的返回值应该返回给谁

  2. 实际返回给了谁

  3. 如何修改

    import time
    def index():
    time.sleep(2) # 模拟一下网络延迟以及代码的效率
    return '欢迎访问博客园主页'
    def timer(func): # func = index
    def inner():
    start_time = time.time()
    ret = func()
    end_time = time.time()
    return ret
    return inner
    index = timer(index) # inner
    print(index()) # print(inner())
    # 实际的返回值返给了inner,为了让返回值与源代码一致,需要进行赋值操作,这样就保证了返回值一致
    # 现在代码已经满足原函数的返回值与装饰器之后的返回值保持一致了,还缺少的就是传参一致.

四、被装饰函数带参数的装饰器

​ 当需要与原代码传参保持一致需要注意一下几点

  1. 明确源代码的传参应该传参给谁

  2. 实际传参给了谁

  3. 如何修改

    import time
    def home(name,age):
    time.sleep(3) # 模拟一下网络延迟以及代码的效率
    print(name,age)
    print(f'欢迎访问{name}主页')
    def timer(func): # func = home
    def inner(*args,**kwargs): # 函数定义时,*代表聚合:所以你的args = ('岁月',18)
    start_time = time.time()
    func(*args,**kwargs) # 函数的执行时,*代表打散:所以*args --> *('岁月',18)--> func('岁月',18)
    end_time = time.time()
    return inner
    home = timer(home)
    home('岁月',18)
    # 这样利用*的打散与聚合的原理,将这些实参通过inner函数的中间完美的传递到给了相应的形参。

五、标准版装饰器

  • 代码优化 : 语法糖,Python给我们提供了一个简化机制,用一个很简单的符号去代替类似home = timer(home)这一句话。

    注意 : 因为涉及函数的调用,@timer一定要放在被装饰函数的上方,否则会报错.

    def timer(func):  # func = home
    def inner(*args,**kwargs):
    start_time = time.time()
    func(*args,**kwargs)
    end_time = time.time()
    return inner
    @timer # 此处代替了home = timer(home)
    def home(name,age):
    time.sleep(3) # 模拟一下网络延迟以及代码的效率
    print(name,age)
    print(f'欢迎访问{name}主页')
    home('岁月',18)
  • 至此标准版的装饰器如下,完全符合代码开放封闭原则:

    def warpter(f):
    def inner(*args,**kwargs)
    # 此处执行被装饰函数之前的操作
    ret=f(*args,**kwargs)
    # 此处执行被装饰函数之后的操作
    return ret
    return inner

六、带参数的装饰器

​ 函数就应该具有函数传参功能,现在要完成的就是装饰器要分情况去判断账号和密码,不同的函数用的账号和密码来源不同,但是之前写的装饰器只能接受一个参数就是函数名,所以现在需要写一个可以接受参数的装饰器

@wrapper_out("qq")此时分以下两步执行

  1. 第一步先执行wrapper_out("qq")函数,得到返回值wrapper

  2. 第二步@与wrapper结合,形成装饰器@wrapper 然后在依次执行

    def user_information(n):
    user_name = input("账号:").strip()
    user_password = input("密码:").strip()
    with open(n,encoding="utf-8")as f :
    for i in f:
    name,password=i.strip().split("|")
    if user_name==name and password==user_password:
    judge[n] = True
    return True
    else:
    return False
    def wrapper_out(n):
    def wrapper(f):
    def inner(*args,**kwargs):
    if judge[n]:
    ret = f(*args, **kwargs)
    return ret
    else:
    if user_information(n):
    ret = f(*args, **kwargs)
    return ret
    else:
    return "账号或密码错误"
    return inner
    return wrapper
    @wrapper_out("qq")
    def user_qq():
    return "欢迎来到qq"
    @wrapper_out("tiktok")
    def user_tiktok():
    return "欢迎来到tiktok"
    judge={"qq":False,"tiktok":False}
    print(user_qq())
    print(user_qq())
    print(user_tiktok())
    print(user_tiktok())

七、多个装饰器装饰一个函数

def wrapper1(func1):  # func1 = f原函数
def inner1():
print('wrapper1 ,before func') # 2
func1()
print('wrapper1 ,after func') # 4
return inner1
def wrapper2(func2): # func2 == inner1
def inner2():
print('wrapper2 ,before func') # 1
func2() # inner1
print('wrapper2 ,after func') # 5
return inner2
@wrapper2 # f = wrapper2(f) 里面的f == inner1 外面的f == inner2
@wrapper1 # f = wrapper1(f) 里面的f == func1 外面的 f == inner1
def f():
print('in f') # 3
f() # inner2()

八、递归函数

  1. 递归函数 : 函数调用方式为函数本身,这种函数叫递归函数,类似while循环.

  2. 注意 : 官网规定默认递归的最大深度1000次,如果你递归超过100次还没有解决这个问题,那么执意使用递归,效率很低。

  3. 函数表达式样式

    def func():
    print("太极")
    func()
    func()
  4. 举例说明

    # 例子
    l1 = [1,2,4,['你好','世界',34,[3,5,[11,3]]],[7, 28],36]
    def func(lis):
    for i in lis:
    if type(i)==list:
    func(i)
    else:
    print(i)
    func(l1)

13.Python略有小成(装饰器,递归函数)的更多相关文章

  1. python之装饰器补充与递归函数与二分查找

    目录 多层装饰器 有参装饰器 递归函数 基本演示 斐波那契数列 总结 小拓展 算法之二分法 简介 举例 总结 多层装饰器 我们已经知道了语法糖的作用是将装饰对象自动装饰到装饰器中,一个语法糖的应用我们 ...

  2. 理解Python中的装饰器//这篇文章将python的装饰器来龙去脉说的很清楚,故转过来存档

    转自:http://www.cnblogs.com/rollenholt/archive/2012/05/02/2479833.html 这篇文章将python的装饰器来龙去脉说的很清楚,故转过来存档 ...

  3. Python的装饰器实例用法小结

    这篇文章主要介绍了Python装饰器用法,结合实例形式总结分析了Python常用装饰器的概念.功能.使用方法及相关注意事项 一.装饰器是什么 python的装饰器本质上是一个Python函数,它可以让 ...

  4. python通过装饰器检查函数参数的数据类型的代码

    把内容过程中比较常用的一些内容记录起来,下面内容段是关于python通过装饰器检查函数参数的数据类型的内容. def check_accepts(f): assert len(types) == f. ...

  5. Python函数装饰器高级用法

    在了解了Python函数装饰器基础知识和闭包之后,开始正式学习函数装饰器. 典型的函数装饰器 以下示例定义了一个装饰器,输出函数的运行时间: 函数装饰器和闭包紧密结合,入参func代表被装饰函数,通过 ...

  6. Python各式装饰器

    Python装饰器,分两部分,一是装饰器本身的定义,一是被装饰器对象的定义. 一.函数式装饰器:装饰器本身是一个函数. 1.装饰函数:被装饰对象是一个函数 [1]装饰器无参数: a.被装饰对象无参数: ...

  7. Python札记 -- 装饰器补充

    本随笔是对Python札记 -- 装饰器的一些补充. 使用装饰器的时候,被装饰函数的一些属性会丢失,比如如下代码: #!/usr/bin/env python def deco(func): def ...

  8. python基础——装饰器

    python基础——装饰器 由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数. >>> def now(): ... print('2015-3-25 ...

  9. 【转】详解Python的装饰器

    原文链接:http://python.jobbole.com/86717/ Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现 ...

随机推荐

  1. Apache NiFi 开发 处理器使用说明

    NIFI的使用: 注意:FlowFile由[属性]和[内容]组成,在解析的过程中这个概念非常重要,因为有些组件操作的是属性,有些组件操作的是内容,在配置组件时Destination配置项的选择很重要, ...

  2. css三角形实现的几种方法的区别

    演变: .triangle{ height: 30px; width: 30px; display: inline-block; border: 30px solid; border-color: # ...

  3. web tools for sublime

    Your code editor is your main development tool; you use it to write and save lines of code. Write be ...

  4. Custom Database Integration Guide

    Introduction This document provides instructions for integrating Openfire authentication, users, and ...

  5. 线程绑定CPU核-sched_setaffinity

    CPU亲合力就是指在Linux系统中能够将一个或多个进程绑定到一个或多个处理器上运行. 一个进程的CPU亲合力掩码决定了该进程将在哪个或哪几个CPU上运行.在一个多处理器系统中,设置CPU亲合力的掩码 ...

  6. 剑指offer24:判断一个二叉树的后序遍历序列是否为二叉搜索树的后序遍历序列

    public static boolean isBSTSequence(int[] s,int l, int r) { if (s == null || r <= 0) return false ...

  7. 1068 Bash游戏 V3

    1068 Bash游戏 V3 题目来源: Ural 1180 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题  收藏  关注 有一堆石子共有N个.A B两个人轮流拿 ...

  8. 【Matlab】调试基础

    1.matlab 调试子程序 在主程序进入子程序前一句加断点,然后step in,可以进入子程序. 但是直接在子程序里设置断点,运行主程序是不能进入子程序的.

  9. VirtualBox下安装MacOS11

    8.键盘选中 “简体中文” -- > "拼音模式".VirtualBox安装Mac OS 10.11 ,安装日期:2016 / 5 / 14 用虚拟机装黑苹果本人也装了不下3 ...

  10. 几个网络模型的示例代码(BlockingModel、OverlappedModel、WSAEventSelect、CompletionRoutine)..c++

    作者的blog:猪)的网络编程世界 几个网络模型的示例代码代码包括了下面几个模型的示例:BlockingModel(阻塞模式).OverlappedModel(基于事件的重叠I/O).WSAEvent ...