在Python中的无参装饰器和有参装饰器

枫铃3年前 (2021-07-10)Python305

装饰器特点:

1.开放封闭原则,即对扩展是开放的,对修改时封闭的;
2.装饰器本质可以是任意可调用的对象,被装饰的对象也可以是任意可调用对象;
3.装饰器的功能是在不修改被装饰器对象源代码以及被装饰器对象的调用方式的前提下为其扩展新功能;
4.装饰器本质是函数,(即装饰其他函数)就是为其他函数添加附加功能。

装饰器其实就是对函数的理解与运用(函数对象与闭包函数)

一 ,典型的案例:

#装饰器的语法:在被装饰对象的正上方的单独一行,@装饰器名字
import time
import random
 
def RunTime(TheCaller):  #定义装饰器
    def MyCaller():
        start_time = time.time()
        TheCaller()
        stop_time=time.time()
        print('run time is %s' %(stop_time-start_time))
    return MyCaller
 
#被装饰函数
@RunTime #等效于index=RunTime(index)
def index():
    time.sleep(random.randrange(2,4))   #可以在1-3秒钟(不包括4秒哟)随机睡眠指定范围的时长。
    print('welecome to INDEX page')
 
@RunTime #home=RunTime(home)
def home():
    time.sleep(random.randrange(1,2))
    print('welecome to HOME page')
 
index() #MyCaller()
home() 
 
#以上代码执行结果如下:
welecome to INDEX page
run time is 2.0000088214874268
welecome to HOME page
run time is 1.0006351470947266

二,多个装饰器的案例

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
#!/usr/bin/env python
#装饰器的语法:在被装饰对象的正上方的单独一行,@装饰器名字
import time
import random
from functools import wraps
 
def RunTime(TheCaller):  #定义装饰器+
    @wraps(TheCaller)       #可以让用户查看帮助信息的时候查看其自己的源代码定义的帮助信息。
    def MyCaller(*args,**kwargs):
        '''
        Runtime's help information
        '''
        start_time = time.time()
        res = TheCaller(*args,**kwargs)
        stop_time=time.time()
        print('run time is %s' %(stop_time-start_time))
        return res
 
    return MyCaller
 
def NewAddAuth(TheCaller):
    def Auth(*args,**kwargs):
        name=input('username: ')
        password=input('password: ')
        if name == 'rianley' and password == '123':
            print('login successful')
            res = TheCaller(*args,**kwargs)
            return res
        else:
            print('login error')
    return Auth
 
#被装饰函数
# @NewAddAuth
@RunTime #等效于index=RunTime(index),装饰器的执行顺序是自下而上。
def Index():
    '''
    Index's help information
    '''
    time.sleep(random.randrange(2,4))   #可以在1-3秒钟(不包括4秒哟)随机睡眠指定范围的时长。
    print('welecome to INDEX page')
    return "rianleycheng"
 
@RunTime #home=RunTime(home)
def Home(name):
    '''
      Home's help information
      '''
    time.sleep(random.randrange(1,2))
    print('welecome to %s HOME page'%(name))
    return 666
 
res1 = Index() #MyCaller()
res2 = Home("程小航")
print("Index return :%s"%(res1))
print("Home return :%s"%(res2))
# print(help(Index))
# print(Index().__doc__)    
#以上代码执行结果如下:
welecome to INDEX page
run time is 3.000018835067749
welecome to 程小航 HOME page
run time is 1.0001890659332275
Index return :rianleycheng
Home return :666

三,有参装饰器

'''
编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登陆成功一次,后续的函数都无需再验证。
''' 
# user_dic = {
#     'rianley':'123',
#     'Golang':"666",
#     'Python':"888",
# }
#
# with open("user.db","w",encoding="utf-8")as f:
#     f.write(str(user_dic))   
 
db_path = "user.db"
 
login_dic ={
    'user':None,
    "status":False,
}
 
def Decorator(AuthType="file"):
    def auth(func):
        def wrapper(*args, **kwargs):
            if AuthType == "file":
                if login_dic['user'] and login_dic['status']:
                    res = func(*args, **kwargs)
                    return res
                username = input("username:")
                password = input("password:")
                with open(db_path, "r", encoding="utf-8")as f:
                    user_dic = eval(f.read())
                if username in user_dic and password == user_dic[username]:
                    print('login successful')
                    login_dic['user'] = username
                    login_dic['status'] = True
                    res = func(*args, **kwargs)
                    return res
                else:
                    print('login error')
            elif AuthType == "ldap":
                print("LDAP认证方式")
            elif AuthType == "MySQL":
                print("MySQL认证方式")
            else:
                print("其他认证方式")
        return wrapper
    return auth
 
@Decorator()
def Index():
    print("Welcome to Index!")
 
@Decorator(AuthType="MySQL")
def home(name):
    print("Welecome %s to home page!"%name)
 
Index()
home("程小航") 
 
#以上代码执行结果如下:
username:rianley
password:123
login successful
Welcome to Index!
MySQL认证方式 

四.小试牛刀

1.编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登陆成功一次,后续的函数都无需再验证。

# user_dic = {
#     'rianley':'123',
#     'Golang':"666",
#     'Python':"888",
# }
#
# with open("user.db","w",encoding="utf-8")as f:
#     f.write(str(user_dic))
   
 
db_path = "user.db"
 
login_dic ={
    'user':None,
    "status":False,
}
 
def auth(func):
    def wrapper(*args,**kwargs):
        if login_dic['user'] and login_dic['status']:
            res = func(*args, **kwargs)
            return res
        username = input("username:")
        password = input("password:")
        with open(db_path, "r", encoding="utf-8")as f:
            user_dic = eval(f.read())
        if username in user_dic and password == user_dic[username]:
            print('login successful')
            login_dic['user'] = username
            login_dic['status'] = True
            res = func(*args,**kwargs)
            return res
        else:
            print('login error')
    return wrapper
 
@auth
def Index():
    print("Welcome to Index!")
 
@auth
def home(name):
    print("Welecome %s to home page!"%name)
 
Index()
home("程小航")
    
以上代码执行结果如下:
username:rianley
password:123
login successful
Welcome to Index!
Welecome 程小航 to home page!

2.编写下载网页内容的函数,要求功能是:用户传入一个URL,函数返回下载页面的内容。

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
from urllib.request import urlopen
import os
 
cache_path=r'cache.txt'
def make_cache(func):
    def wrapper(*args,**kwargs):
        if os.path.getsize(cache_path):#说明有缓存
            print('\033[45m=========有缓存=========\033[0m')
            with open(cache_path,'rb') as f:
                res=f.read()
 
        else:
            res=func(*args,**kwargs) #下载
            with open(cache_path,'wb') as f: #制作缓存
                f.write(res)
 
        return res
 
    return wrapper
 
@make_cache
def get(url):
    return urlopen(url).read()
 
 
print('============first============')
print(get('http://www.cnblogs.com/rianley'))
print('============second===========')
print(get('http://www.cnblogs.com/rianley'))
print('============third============')
print(get('http://www.cnblogs.com/rianley'))   

3.装饰器包装原函数案例

FuncDict={}
 
def MakeDict(key):
    def deco(func):
        FuncDict[key]=func
        # def wrapper(*args,**kwargs):          #此行及以下3行可以不写,这样就可以达到隐藏你原来函数的名字。
        #     res = func(*args,**kwargs)
        #     return res
        # return wrapper
    return deco 
 
@MakeDict("one")
def First():
    print("From Shell")
  
@MakeDict("two")
def Second():
    print("From Second")
 
@MakeDict("three")
def Third():
    print("From Third")
 
print(FuncDict)
 
while True:
    cmd = input(">>>:").strip()
    if  cmd in FuncDict:
        FuncDict[cmd]()  
 
#以上代码执行结果如下:
{'one': <function First at 0x027E38E8>, 'two': <function Second at 0x027E3810>, 'three': <function Third at 0x027E38A0>}
>>>:three
From Third
>>>:one
From Shell
>>>:two
From Second
>>>:
>>>:
>>>:

相关文章

Django中cookie和session的存、取、删除

Django中: cookie的存: response = HttpResponse('登陆成功')...

Python基础教程:回调在编程中的含义

Python基础教程:回调在编程中的含义

回调函数的最初需求背景...

Python教程:多变量的灵活处理

今天就和大家介绍一个最基...

python类的命名空间与组合

一、类的命名空间 定义:我们在创建一个类的时候就会创建一个类的命名空间,用来存储类中定义的所有的名字,这些名字称为...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。