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. HBase存储方案设计

    需求描述 将数据记录持久化存储在HBase中,需要支持如下功能: 支持高吞吐量读写操作,实时采集10,000条/秒: 支持动态添加字段: 支持服务端过滤: 支持部分字段修改. 设计方案 按列存储 优点 ...

  2. tomcat 1)启动时不识别执行启动命令 2)启动报错 3)关闭不了,用myEclipse启动时显示jvm_bind,端口占用

  3. 我的.emacs文件,用于C/C++及shell编程。

    1. [代码]我的.emacs文件,用于C/C++及shell编程.;;我的配置;;1.基本配置;;外观配置***************;;禁用启动画面(setq inhibit-startup-m ...

  4. 三年java软件工程师应有的技技能

    摘要:http://blog.csdn.net/jieinasiainfo/article/details/51177729 http://blog.csdn.net/kangqianglong/ar ...

  5. html5--1.15 style元素与HTML样式基础

    html5--1.15 style元素与HTML样式基础 学习要点: 1.引入样式的三种方式2.了解style元素插入内联样式表与内部样式表 1.引入样式的三种方式 1.外部样式表:通过 link元素 ...

  6. hdu 4704 sum(费马小定理+快速幂)

    题意: 这题意看了很久.. s(k)表示的是把n分成k个正整数的和,有多少种分法. 例如: n=4时, s(1)=1     4 s(2)=3     1,3      3,1       2,2 s ...

  7. linux增加vlan网卡配置

    1.编辑文件/etc/sysconfig/network在里面添加一行:VLAN=yes2.再生成网卡设备的配置文件ifcfg-eth1.10和ifcfg-eth1.240cd /etc/syscon ...

  8. poj3709 K-Anonymous Sequence[贪心+斜率优化dp]

    地址 n个数,可进行把一个数减小的操作,代价为减小的值.现求使数列任意一个数都存在至少k-1个数和他相同,问操作的最小代价. 可以先考虑最小的数,由于只能减,所以必须得至少k-1个数减为最小数,贪心策 ...

  9. scala & spark实战

    java.lang.Long is not a valid external type for schema of string   java.lang.RuntimeException: Error ...

  10. css水平居中方式

    1. text-align:center 这种方式只适合于内联元素或者文字处于块元素当中是,给块元素设置这个,那么块元素当中的文字或者内联元素则居中.兼容各种浏览器 <div class=&qu ...