第九篇 裝飾器


一 什么是裝飾器

器即函數

裝飾即修飾,意指為其他函數添加新功能

裝飾器定義:本質就是函數,功能是為其他函數添加新功能

二 裝飾器需要遵循的原則

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.函數的返回值是一個函數名
  作用:不修改函數的調用方式
  不足:不能添加新功能

五 函數嵌套

 1 def father(name):
 2     print('from father %s' %name)
 3     def son():
 4         print('from son')
 5         def grandson():
 6             print('from grandson')
 7         grandson()
 8     son()
 9 
10 father('林海峰')

六 閉包

 1 '''
 2 閉包:在一個作用域里放入定義變量,相當於打了一個包
 3 '''
 4 def father(name):
 5     def son():
 6         # name='alex'
 7         print('我爸爸是 [%s]' %name)
 8         def grandson():
 9             # name='wupeiqi'
10             print('我爺爺是 [%s]' %name)
11         grandson()
12     son()
13 
14 father('林海峰')

七 無參裝飾器

無參裝飾器=高級函數+函數嵌套

基本框架

1 #這就是一個實現一個裝飾器最基本的架子
2 def timer(func):
3     def wrapper():
4         func()
5     return wrapper

加上參數

1 def timer(func):
2     def wrapper(*args,**kwargs):
3         func(*args,**kwargs)
4     return wrapper

加上功能

1 import time
2 def timer(func):
3     def wrapper(*args,**kwargs):
4         start_time=time.time()
5         func(*args,**kwargs)
6         stop_time=time.time()
7         print('函數[%s],運行時間是[%s]' %(func,stop_time-start_time))
8     return wrapper

加上返回值

1 import time
2 def timer(func):
3     def wrapper(*args,**kwargs):
4         start_time=time.time()
5         res=func(*args,**kwargs)
6         stop_time=time.time()
7         print('函數[%s],運行時間是[%s]' %(func,stop_time-start_time))
8         return res
9     return wrapper

使用裝飾器

1 def cal(array):
2     res=0
3     for i in array:
4         res+=i
5     return res
6 
7 cal=timer(cal)
8 cal(range(10))

語法糖@

1 @timer  #@timer就等同於cal=timer(cal)
2 def cal(array):
3     res=0
4     for i in array:
5         res+=i
6     return res
7 
8 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(u'function 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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM