程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python進階系列(五)

編輯:Python

目錄

裝飾器

使用場景

授權(Authorization)

日志(Logging)

帶參數的裝飾器

在函數中嵌入裝飾器

裝飾器類


裝飾器

使用場景

現在我們來看一下裝飾器在哪些地方特別耀眼,以及使用它可以讓一些事情管理起來變得更簡單。

授權(Authorization)

裝飾器能有助於檢查某個人是否被授權去使用一個web應用的端點(endpoint)。它們被大量

使用於Flask和Django web框架中。這裡是一個例子來使用基於裝飾器的授權:

from functools import wraps
def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            authenticate()
        return f(*args, **kwargs)
return decorated

日志(Logging)

日志是裝飾器運用的另一個亮點。這是個例子:

from functools import wraps
def logit(func):
    @wraps(func)
    def with_logging(*args, **kwargs):
        print(func.__name__ + " was called")
        return func(*args, **kwargs)
    return with_logging
@logit
def addition_func(x):
    """Do some math."""
    return x + x
result = addition_func(4)
# Output: addition_func was called

我敢肯定你已經在思考裝飾器的一個其他聰明用法了。

帶參數的裝飾器

來想想這個問題,難道@wraps不也是個裝飾器嗎?但是,它接收一個參數,就像任何普通的函數能做的那樣。那麼,為什麼我們不也那樣做呢?

這是因為,當你使用@my_decorator語法時,你是在應用一個以單個函數作為參數的一個包裹函數。記住,Python裡每個東西都是一個對象,而且這包括函數!記住了這些,我們可以編寫一下能返回一個包裹函數的函數。

在函數中嵌入裝飾器

我們回到日志的例子,並創建一個包裹函數,能讓我們指定一個用於輸出的日志文件。

from functools import wraps
def logit(logfile='out.log'):
    def logging_decorator(func):
        @wraps(func)
        def wrapped_function(*args, **kwargs):
            log_string = func.__name__ + " was called"
            print(log_string)
            # 打開logfile,並寫入內容
            with open(logfile, 'a') as opened_file:
                # 現在將日志打到指定的logfile
                opened_file.write(log_string + '\n')
            return func(*args, **kwargs)
        return wrapped_function
    return logging_decorator
@logit()
def myfunc1():
    pass
myfunc1()
# Output: myfunc1 was called
# 現在一個叫做 out.log 的文件出現了,裡面的內容就是上面的字符串
@logit(logfile='func2.log')
def myfunc2():
    pass
myfunc2()
# Output: myfunc2 was called
# 現在一個叫做 func2.log 的文件出現了,裡面的內容就是上面的字符串

裝飾器類

現在我們有了能用於正式環境的logit裝飾器,但當我們的應用的某些部分還比較脆弱時,異常也許是需要更緊急關注的事情。比方說有時你只想打日志到一個文件。而有時你想把引起你注意的問題發送到一個email,同時也保留日志,留個記錄。這是一個使用繼承的場景,但目前為止我們只看到過用來構建裝飾器的函數。

幸運的是,類也可以用來構建裝飾器。那我們現在以一個類而不是一個函數的方式,來重新構建logit。

from functools import wraps
class logit(object):
    def __init__(self, logfile='out.log'):
        self.logfile = logfile
    def __call__(self, func):
        @wraps(func)
        def wrapped_function(*args, **kwargs):
            log_string = func.__name__ + " was called"
            print(log_string)
            # 打開logfile並寫入
            with open(self.logfile, 'a') as opened_file:
                # 現在將日志打到指定的文件
                opened_file.write(log_string + '\n')
            # 現在,發送一個通知
            self.notify()
            return func(*args, **kwargs)
        return wrapped_function
    def notify(self):
        # logit只打日志,不做別的
        pass

這個實現有一個附加優勢,在於比嵌套函數的方式更加整潔,而且包裹一個函數還是使用跟以前一樣的語法:

@logit()
def myfunc1():
    pass

現在,我們給logit創建子類,來添加email的功能(雖然email這個話題不會在這裡展開)。

class email_logit(logit):
    一個logit的實現版本,可以在函數調用時發送email給管理員


    def __init__(self, email='[email protected]', *args, **kwargs)
        self.email = email
        super(logit, self).__init__(*args, **kwargs)
    def notify(self):
        # 發送一封email到self.email
        # 這裡就不做實現了
        pass

從現在起,@email_logit將會和@logit產生同樣的效果,但是在打日志的基礎上,還會多發送一封郵件給管理員。


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved