python中的无参装饰器和有参装饰器

该博客严禁抄袭: 版权所有,盗版必究!

装饰器特点:

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

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

一 ,典型的案例:
#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianleycheng
#blog:http://www.cnblogs.com/rianley

#装饰器的语法:在被装饰对象的正上方的单独一行,@装饰器名字
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

  

二,多个装饰器的案例

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianleycheng
#blog:http://www.cnblogs.com/rianley
#装饰器的语法:在被装饰对象的正上方的单独一行,@装饰器名字
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

 

三,有参装饰器

 

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianleycheng
#blog:http://www.cnblogs.com/rianley

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


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

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley


# 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,函数返回下载页面的内容。

 

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley



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.装饰器包装原函数案例

#!/usr/bin/env python
#_*_coding:utf-8_*_
#@author :rianley
#blog:http://www.cnblogs.com/rianley

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

  

心灵鸡汤: 莫让惰性,成为惯性  (不要让懒惰成为习惯!)

 

欢迎加入 程序员的自我修养 群:687226766

 
 
posted @ 2018-06-01 14:44  rianley  阅读(236)  评论(0编辑  收藏  举报