码迷,mamicode.com
首页 > 编程语言 > 详细

python学习---装饰器

时间:2018-11-23 22:53:12      阅读:276      评论:0      收藏:0      [点我收藏+]

标签:运行时   isp   改变   open   ace   rand   原则   enumerate   none   

什么是装饰器

器即函数

装饰即修饰,意指为其他函数添加新功能

装饰器定义:本质就是函数,功能是为其他函数添加新功能

装饰器需要遵循的原则

1.不修改被装饰函数的源代码(开放封闭原则)

2.为被装饰函数添加新功能后,不修改被修饰函数的调用方式

实现装饰器知识储备

装饰器=高阶函数+函数嵌套+闭包

高阶函数

高阶函数定义:
1.函数接收的参数是一个函数名

2.函数的返回值是一个函数名

3.满足上述条件任意一个,都可称之为高阶函数

技术分享图片
def foo():
    print(我的函数名作为参数传给高阶函数)
def gao_jie1(func):
    print(我就是高阶函数1,我接收的参数名是%s %func)
    func()

def gao_jie2(func):
    print(我就是高阶函数2,我的返回值是%s %func)
    return func

gao_jie1(foo)
gao_jie2(foo)
高阶函数示范
技术分享图片
#高阶函数应用1:把函数当做参数传给高阶函数
import time
def foo():
    print(from the foo)

def timmer(func):
    start_time=time.time()
    func()
    stop_time=time.time()
    print(函数%s 运行时间是%s %(func,stop_time-start_time))
timmer(foo)
#总结:我们确实为函数foo增加了foo运行时间的功能,但是foo原来的执行方式是foo(),现在我们需要调用高阶函数timmer(foo),改变了函数的调用方式
把函数当做参数传给高阶函数
技术分享图片
#高阶函数应用2:把函数名当做参数传给高阶函数,高阶函数直接返回函数名
import time
def foo():
    print(from the foo)

def timmer(func):
    start_time=time.time()
    return func
    stop_time=time.time()
    print(函数%s 运行时间是%s %(func,stop_time-start_time))
foo=timmer(foo)
foo()
#总结:我们确实没有改变foo的调用方式,但是我们也没有为foo增加任何新功能
函数返回值是函数名

高阶函数总结
1.函数接收的参数是一个函数名
  作用:在不修改函数源代码的前提下,为函数添加新功能,
  不足:会改变函数的调用方式
2.函数的返回值是一个函数名
  作用:不修改函数的调用方式
  不足:不能添加新功能

函数嵌套

def father(name):
    print(from father %s %name)
    def son():
        print(from son)
        def grandson():
            print(from grandson)
        grandson()
    son()

father(康明)

 闭包

‘‘‘
闭包:在一个作用域里放入定义变量,相当于打了一个包
‘‘‘
def father(name):
    def son():
        # name=‘alex‘
        print(我爸爸是 [%s] %name)
        def grandson():
            # name=‘wupeiqi‘
            print(我爷爷是 [%s] %name)
        grandson()
    son()

father(康明)

无参装饰器

无参装饰器=高级函数+函数嵌套

基本框架

 #这就是一个实现一个装饰器最基本的架子
 def timer(func):
     def wrapper():
         func()
     return wrapper

加上参数

 def timer(func):
     def wrapper(*args,**kwargs):
         func(*args,**kwargs)
     return wrapper

加上功能

import time
def timer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        func(*args,**kwargs)
        stop_time=time.time()
        print(函数[%s],运行时间是[%s] %(func,stop_time-start_time))
    return wrapper

加上返回值

import time
def timer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print(函数[%s],运行时间是[%s] %(func,stop_time-start_time))
        return res
    return wrapper

使用装饰器

def cal(array):
    res=0
    for i in array:
        res+=i
    return res

cal=timer(cal)
cal(range(10))

语法糖@

@timer  #@timer就等同于cal=timer(cal)
def cal(array):
    res=0
    for i in array:
        res+=i
    return res

cal(range(10))

装饰器应用示例

技术分享图片
user_list=[
    {name:alex,passwd:123},
    {name:linhaifeng,passwd:123},
    {name:wupeiqi,passwd:123},
    {name:yuanhao,passwd:123},
]

current_user={username:None,login:False}

def auth_deco(func):
    def wrapper(*args,**kwargs):
        if current_user[username] and current_user[login]:
            res=func(*args,**kwargs)
            return res
        username=input(用户名: ).strip()
        passwd=input(密码: ).strip()

        for index,user_dic in enumerate(user_list):
            if username == user_dic[name] and passwd == user_dic[passwd]:
                current_user[username]=username

                current_user[login]=True
                res=func(*args,**kwargs)
                return res
                break
        else:
            print(用户名或者密码错误,重新登录)

    return wrapper

@auth_deco
def index():
    print(欢迎来到主页面)

@auth_deco
def home():
    print(这里是你家)

def shopping_car():
    print(查看购物车啊亲)

def order():
    print(查看订单啊亲)

print(user_list)
# index()
print(user_list)
home()
无参装饰器
技术分享图片
user_list=[
    {name:alex,passwd:123},
    {name:linhaifeng,passwd:123},
    {name:wupeiqi,passwd:123},
    {name:yuanhao,passwd:123},
]

current_user={username:None,login:False}
def auth(auth_type=file):
    def auth_deco(func):
        def wrapper(*args,**kwargs):
            if auth_type == file:
                if current_user[username] and current_user[login]:
                    res=func(*args,**kwargs)
                    return res
                username=input(用户名: ).strip()
                passwd=input(密码: ).strip()

                for index,user_dic in enumerate(user_list):
                    if username == user_dic[name] and passwd == user_dic[passwd]:
                        current_user[username]=username
                        current_user[login]=True
                        res=func(*args,**kwargs)
                        return res
                        break
                else:
                    print(用户名或者密码错误,重新登录)
            elif auth_type == ldap:
                print(巴拉巴拉小魔仙)
                res=func(*args,**kwargs)
                return res
        return wrapper
    return auth_deco


#auth(auth_type=‘file‘)就是在运行一个函数,然后返回auth_deco,所以@auth(auth_type=‘file‘)
#就相当于@auth_deco,只不过现在,我们的auth_deco作为一个闭包的应用,外层的包auth给它留了一个auth_type=‘file‘参数
@auth(auth_type=ldap)
def index():
    print(欢迎来到主页面)

@auth(auth_type=ldap)
def home():
    print(这里是你家)

def shopping_car():
    print(查看购物车啊亲)

def order():
    print(查看订单啊亲)

# print(user_list)
index()
# print(user_list)
home()
带参装饰器

超时装饰器

技术分享图片
import sys,threading,time


class KThread(threading.Thread):

    """A subclass of threading.Thread, with a kill()

    method.



    Come from:

    Kill a thread in Python:

    http://mail.python.org/pipermail/python-list/2004-May/260937.html

    """

    def __init__(self, *args, **kwargs):

        threading.Thread.__init__(self, *args, **kwargs)

        self.killed = False



    def start(self):

        """Start the thread."""

        self.__run_backup = self.run

        self.run = self.__run      # Force the Thread to install our trace.

        threading.Thread.start(self)



    def __run(self):

        """Hacked run function, which installs the

        trace."""

        sys.settrace(self.globaltrace)

        self.__run_backup()

        self.run = self.__run_backup



    def globaltrace(self, frame, why, arg):

        if why == call:

          return self.localtrace

        else:

          return None



    def localtrace(self, frame, why, arg):

        if self.killed:

          if why == line:

            raise SystemExit()

        return self.localtrace



    def kill(self):

        self.killed = True



class Timeout(Exception):

    """function run timeout"""



def timeout(seconds):

    """超时装饰器,指定超时时间

    若被装饰的方法在指定的时间内未返回,则抛出Timeout异常"""

    def timeout_decorator(func):

        """真正的装饰器"""



        def _new_func(oldfunc, result, oldfunc_args, oldfunc_kwargs):

            result.append(oldfunc(*oldfunc_args, **oldfunc_kwargs))



        def _(*args, **kwargs):

            result = []

            new_kwargs = { # create new args for _new_func, because we want to get the func return val to result list

                oldfunc: func,

                result: result,

                oldfunc_args: args,

                oldfunc_kwargs: kwargs

            }

            thd = KThread(target=_new_func, args=(), kwargs=new_kwargs)

            thd.start()

            thd.join(seconds)

            alive = thd.isAlive()

            thd.kill() # kill the child thread

            if alive:

                raise Timeout(ufunction run too long, timeout %d seconds. % seconds)

            else:

                return result[0]

        _.__name__ = func.__name__

        _.__doc__ = func.__doc__

        return _

    return timeout_decorator


@timeout(5)

def method_timeout(seconds, text):

    print(start, seconds, text)

    time.sleep(seconds)

    print(finish, seconds, text)

    return seconds


method_timeout(6,asdfasdfasdfas)
View Code

 

python学习---装饰器

标签:运行时   isp   改变   open   ace   rand   原则   enumerate   none   

原文地址:https://www.cnblogs.com/kangming-/p/10010072.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!