zoukankan      html  css  js  c++  java
  • python中的装饰器

    python语言中的装饰器应该算是这门语言中的一个难点了,作为一个初学者,好像也知道是怎么回事,可是否真正理解了,那还得存疑。最近偶然看到老男孩的Egon老师的视频,我才觉得真正明白装饰器是怎么一回事了。Egon老师那种抽丝剥茧式的讲解,真是让人耳目一新。虽然有些时候略显繁琐,但对于一个困难知识点来说,再没有这种方式更好的讲解了。接下来,我就着刚看过视频的热乎劲儿,把我对装饰器的理解记录下来,以防止哪一天忘记了。

    • 什么是装饰器
      - 装饰器一种特殊对象,可以给其它对象添加功能,而不改变所装饰对象的使用方式。比如说:如果一个函数被一个装饰器装饰,那么从用户的角度来看,应该感觉不到有任何变化,函数的调用方式,参数以及返回值都不发生任何变化。
      - 装饰器用到了一个Python中的一个重要概念:闭包。什么是闭包?条件有两个:一是一定要有一个内部函数。二是这个内部函数一定要访问包含这个内部函数的外层函数的变量。
      - 还利用了Python中的函数的特性:可以作为参数传递,也可以作为返回值被返回。
    • 如何来写一个装饰器(以函数装饰器为例)
      - 我们先来考虑,如何给一个函数增加功能,却不改变它的调用方式。
    # sol3 - 1: 通过在内外层函数中使用两次(*args, **kwargs),可以把外层函数的参数原封不动地传递到内层。
    # 从而就可以把内层函数的参数写活,但是变更了调用方式,要通过wrapper来调用index
    
    def wrapper(*args, **kwargs):
        start = time.time()
        index(*args, **kwargs)
        stop = time.time()
        print(stop - start)
    
    
    wrapper('xiaolee', 'zd')
    
    # sol 3 -2: 要想不改变函数的调用方式,只能通过在wrapper函数外再包上一层函数。这个方案还不能接收内层函数的返回值。
    def timer(func):
        def wrapper(*args, **kwargs):
            start = time.time()
            func(*args, **kwargs)
            stop = time.time()
            print(stop - start)
        return wrapper
    
    
    index = timer(index)
    index('ggg', 'dddd')
    
    
    # sol3 - 3:通过res变量接收内层函数的返回值,并作为wrapper函数的返回值返回。
    def timer(func):
        def wrapper(*args, **kwargs):
            start = time.time()
            res = func(*args, **kwargs)
            stop = time.time()
            print(stop - start)
            return res
        return wrapper
    
    
    index = timer(index)
    print(index('zz', 'yy'))
    # sol 4: 语法糖
    def timer(func):
        def wrapper(*args, **kwargs):
            start = time.time()
            res = func(*args, **kwargs)
            stop = time.time()
            print(stop - start)
            return res
        return wrapper
    
    @timer
    def index(x, y):
        time.sleep(1)
        print('heloo %s, your company %s' % (x, y))
    
    index('xxxx', 'ccccc')     
    
    • 带参数的装饰器
    # 带参装饰器:实际上,一层闭包就可以将一个参数向内传递一层。
    # 以加简单的认证功能为例
    def authentication():
        user = input('Please input your username: ').strip()
        password = input('Please input your password: ').strip()
        if user == 'zylee' and password == 'wlsoft':
            print('authentication successful!!!')
            return True
        else:
            print('authentication failed!!!')
            return False
    
    def auth(db_style):
        def deco(func):
            def wrapper(*args, **kwargs):
                # auth code
                if db_style == 'mysql':
                    if authentication():
                        res = func(*args, **kwargs)
                        return res
                elif db_style == 'file' and authentication():
                    if authentication():
                        res = func(*args, **kwargs)
                        return res
                else:
                    print("error!!!!")
            return wrapper
        return deco
    
    # @auth('mysql')这一行的功能:先执行auth('mysql'),将deco作为返回值返回。实际上@作用在了deco上。
    # @的作用有二:一是将所装饰的函数的地址作为参数传给deco。二是deco(index)的返回值赋给index。运行之后,相当于执行wrapper函数。
    @auth('mysql')   
    def index(x, y):
        print('hello, %s and %s' % (x, y))
    
    index('a', 'b')
    
  • 相关阅读:
    C#程序调试
    jsp连接sql数据库
    SQL记录
    对于和/的小问题:证明路径中可以混合使用斜杠和反斜杠
    集合初识
    details.jsp页面的 response.addCookie(cookie);报错&tomcat高版本下的Cookie问题
    sql查询操作—顺序查询
    myeclipse使用Microsoft JDBC Driver 6.0 for SQL Server连接sql
    JavaScript、Java、C#关于for循环的比较
    关于jsp动作元素的一点疑惑
  • 原文地址:https://www.cnblogs.com/xiaolee-tech/p/13474622.html
Copyright © 2011-2022 走看看