装饰器 递归

装饰器

开放封闭原则

  • 开放 : 对扩展是开放的 ( 允许代码扩展、添加新功能 )
  • 封闭 : 对 修改 , 源代码 以及 调用方式 是封闭的

初识装饰器

定义:

  • 装饰器本身就是一个函数 , 在不改变原被装饰的函数的源代码以及调用方式下,为其添加一个额外的功能。
import time # (格林尼治时间 , 也叫时间截)  测试执行效率

def fun(): #2.00022554397583
    time.sleep(2)  # 模拟一下网络延迟以及代码的效率
    print("欢迎访问博客园主页")

def index(): #2.001535654067993
    time.sleep(2)  # 模拟一下网络延迟以及代码的效率
    print('欢迎访问博客园首页')
    
def home(): #3.000067710876465
    time.sleep(3)  # 模拟一下网络延迟以及代码的效率
    print(f'欢迎访问主页')
    
def timer(func):  # func = index
    def inner():
        start_time = time.time()
        func()
        end_time = time.time()
        print(f'此函数的执行效率为{end_time-start_time}')
    return inner


timer(fun)()

带返回值的装饰器

import time
def index():
    time.sleep(2)  # 模拟一下网络延迟以及代码的效率
    print('欢迎访问博客园主页')
    return '访问成功'

def timer(func):  # func = index
    def inner():
        start_time = time.time()
        ret = func()  # '访问成功'
        end_time = time.time()
        print(f'此函数的执行效率为{end_time - start_time}')
        return ret  # '访问成功'

    return inner


index = timer(index)  # inner
print(index())  # print(inner())
print(timer(index)())   # '访问成功'

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

单一参数的装饰器

# 单一参数的装饰器
import time
def index():
    time.sleep(2)  # 模拟一下网络延迟以及代码的效率
    print('欢迎访问博客园主页')
    return '访问成功'

def home(name):
    time.sleep(3)  # 模拟一下网络延迟以及代码的效率
    print(f'欢迎访问{name}主页')

def timer(func):  # func = home
    def inner(name):
        start_time = time.time()
        func(name)  # home(name) == home('太白')
        end_time = time.time()
        print(f'此函数的执行效率为{end_time-start_time}')
    return inner

# 要想timer装饰home函数怎么做?
home = timer(home)
home('太白')  # 注意将返回给 inner(name)返回值 会返回给timer(func)  None

动态参数的装饰器(举例)

# 动态参数的装饰器

import time
def index():
    time.sleep(2)  # 延迟两秒执行下面的代码
    print("欢迎访问博客园主页")
    return "访问成功"

def home(name,age):
    time.sleep(3)
     print(f"欢迎访问{age}岁的{name}的博客园主页")
    
def timer(func):
    def inner(*args,**kwargs):  # 形参位置 *聚合:args = ('太白',18)
        star_time = time.time()
        func(*args,**kwargs)    # 执行位置的*是打散  func('太白',18)
        stop_time = time.time()
        print(f"此函数的执行效率是{stop_time - star_time}")
        return "好靓的发型"
    return inner


home = timer(home)
home("太白",22)
# 在被修饰函数(home)上面加上@装饰器函数名(timer),就等同于那句话 home = timer(home)
# @timer 相当于 home = timer(home)
import time


def timer(func):
    def inner(*args, **kwargs):  # 形参位置 *聚合:args = ('太白',18)
        star_time = time.time()
        #  func(*args, **kwargs)  # 执行位置的*是打散  func('太白',18)
        ret = func(*args, **kwargs)  # 带返回值的原函数
        stop_time = time.time()
        print(f"此函数的执行效率是{stop_time - star_time}")
        return ret

    return inner


@timer 
def home(name, age):
    time.sleep(3)
    print(f"欢迎访问{age}岁的{name}的博客园主页")
    return true


home("太白", 23)
print(home("太白", 23))

标准版装饰器

代码优化:语法糖 @ / 优化语法

  • 在被修饰函数(home)上面加上@ + 装饰器函数名(timer),就等同于那句话 home = timer(home)

语法糖@的执行方式

  • @ 会向下读一行 , 将原函数的函数存到内存 传到装饰器 函数的形参 上 并将原函数名() = 装饰器函数名(原函数名)

标准版的装饰器

def wrapper(func):  # wrapper 包装
    def inner(*args,**kwargs):
        '''执行被装饰函数之前的操作'''
        ret = func
        '''执行被装饰函数之后的操作'''
        return ret
    return inner

装饰器→简单登录

# 简单登录验证
ogin = {"flag":False}
# flag = False
def auth(f):
    def inner(*args,**kwargs):
        # global flag   # 在函数最前面先声明 要改变全局变量 flag
        if login["flag"]:
        # if flag:
            ret = f(*args,**kwargs)
            return ret
        user = input("user>>>")
        passwords = input("passwords>>>")
        if user.strip() == "杨泽涛很帅" and passwords.strip() == "确实帅":
            login["flag"] = True
            # flag = True
            ret = f(*args,**kwargs)
            
            return ret
            
    return inner

@auth
def article():
    print('欢迎访问文章页面')

@auth
def diary():
    print('欢迎访问日记页面')

@auth
def comment():
    print('欢迎访问评论页面')

article()
diary()
comment()

装饰器→自定义循环原函数

def wrapper(f):
    def inner(*args,**kwargs):
        for i in range(*args):
            f(*args,**kwargs)
            
     return inner

@wrapper
def func(n):
    print("没错循环的我")

func(n)

装饰器 → 录入文件时间

import time
def wrapper(f):
    def inner(*args,**kwargs):
        start_time = time.localtime()
        ret = time.strftime("%Y-%m-%d %H:%M:%S", start_time) # 当前时间节点 ymdhms → 年月日时分秒
        f()
        ret_1 = f.__name__
        with open ("文件时间录入.excel",mode = "r+",encoding = "utf-8") as file_1:
            file_1.seek(0,2)
            file_1.write(f"\n{ret_1}_{ret}")
            
    return inner

@wrapper
def func():
    print("快来录入")
    
    
func()

# start_time = time.localtime()  
# ret = time.strftime("%Y-%m-%d %H:%M:%S", start_time)
# 自动生成指定格式的日期串  func_2019-06-24 17:56:36

装饰器 → 限制该函数被调用的频率

# 请实现一个装饰器,限制该函数被调用的频率,如3秒一次(借助于time模块,time.time())
import time
'''
if 第二次执行的时间 - 第一次执行的时间 > 3: 逆推法
   第一次时间节点: 123443543.546  - 0  肯定 > 3
   第二次进入:time.time() 123443545.546  - 123443543.546 < 3''''


def wrapper(f):
    t = 0
    def inner(*args,**kwargs):
        nonlocal t
        if time.time() - t > 3:
            ret = f(*args,**kwargs)
            return ret
            
        
    return inner 

@wrapper
def func():
    print("666")
    
func()
time.sleep(3)
func()

带参数的装饰器

  • 装饰器里多套了一层函数来判定多项参数的选择结果
login = False
def auth(x):
    
    def auth2(func):
        
        def inner(*args,**kwargs):
            global login
            
            if login:
                ret = func()
                return ret
            
            if x = "wechat":
                user = input(">>>用户名:").strip()
                passwords = input(">>>密码:").strip()
                if user == "杨泽涛" and passwords == "123":
                    login = True
                    ret = func()
                    return ret
                
            if x = "QQ":
                user = input(">>>用户名:").strip()
                passwords = input(">>>密码:").strip()
                if user == "杨泽涛" and passwords == "123":
                    login = True
                    ret = func()
                    return ret   
                
        return inner
    
    return auth2

@auth("wechat")
def jitter():
    print("欢迎回到抖音")
    
@auth("QQ")
def pipishrimp():
    print("皮皮虾等你好久了")
    
jitter()
pipishrimp()

多个装饰器装一个参数

def wrapper_1(f1):
    
    def inner_1(*args,**wkargs):
        print("wrapper_1,before f1")
        f1(*args,**wkargs)
        print("wrapper_1,after f1")
    
    return inner_1

def wrapper_2(f2):
    
    def inner_2(*args,**wkargs):
        print("wrapper_2,before f2")
        f2(*args,**wkargs)
        print("wrapper_2,after f2,")
        
    return inner_2

@wrapper_2
@wrapper_1
def func():
    print("666")

func() 
# 打印结果   
'''
wrapper_2,before f2
wrapper_1,before f1
666
wrapper_1,after f1
wrapper_2,after f2
''''

递归函数 (recursion )

  • 在一个函数里在调用这个函数本身 / 递归的最大深度:998 , 最多执行到997
  • 人理解循环,神理解递归
  • 可以使用递归来遍历各种树形结构, 比如我们的文件夹系统. 可以使用递归来遍历该文件夹中的所有文件
  • 有规律的线性结构 有些适合用递归

自定义递归深度

import sys #  调用系统
print(sys.setrecursionlimit(10000))  # 设置默认值递归深度
def foo(n):
    print(n)
    n += 1
    foo(n)
foo(1)

有规律的数值差 / 递归

def age(n):
    if n == 1:
        return 40
    else:
        return age(n-1)+2

print(age(4))

遍历列表 / 递归

l1 = [1, 3, 5, ['22','python', 34, [33, 55, [11,33]]], [77, 88],66]

def func(alist):
    for i in alist:
        if type(i) == list:
            func(i)
        else:
            print(i)
func(l1)


posted @ 2019-06-17 15:31  樊xs  阅读(289)  评论(0编辑  收藏  举报