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

枫铃4年前 (2021-07-10)Python229

装饰器特点:

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
>>>:
>>>:
>>>:

相关文章

利用python同步windows和linux文件

写python脚本的初衷,每次在windows编辑完文件后,想同步到linux上去,只能够登录服务器,...

爬虫基本原理

爬虫基本原理 一、爬虫是什么? 百度百科和维基百科对网络爬虫的定义:简单来说爬虫就是抓取目标网站内容的工具,一般是根据定义的行...

Django 函数和方法的区别

函数和方法的区别 1、函数要手动传self,方法不用传 2、如果是一个函数,用类名去调用,如果是一个方法...

Django 知识补漏单例模式

单例模式:(说白了就是)创建一个类的实例。在 Python 中,我们可以用多种方法来实现单例模式&#x...

Django基础知识MTV

Django简介 Django是使用Python编写的一个开源Web框架。可以用它来快速搭建一个高性能的网站。 Django也是一个MVC框架。但是在Dj...

Python mysql 索引原理与慢查询优化

一 介绍 为何要有索引? 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,...

发表评论

访客

看不清,换一张

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