婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > python 裝飾器的使用與要點

python 裝飾器的使用與要點

熱門標簽:開封語音外呼系統代理商 開封自動外呼系統怎么收費 地圖標注線上如何操作 400電話辦理哪種 手機網頁嵌入地圖標注位置 河北防封卡電銷卡 應電話機器人打電話違法嗎 電銷機器人的風險 天津電話機器人公司

一、裝飾器使用場景

經常用于有切面需求的場景,比如:插入日志、性能測試、事務處理、緩存、權限校驗等場景。裝飾器是解決這類問題的絕佳設計,有了裝飾器,我們就可以抽離出大量與函數功能本身無關的雷同代碼并繼續重用。

概括的講,裝飾器的作用就是為已經存在的對象添加額外的功能。

二、為什么需要裝飾器

1、先來看一個簡單例子:

def foo():
print('i am foo')

2、增加需求

現在有一個新的需求,希望可以記錄下函數的執行日志,于是在代碼中添加日志代碼:

def foo():
    print('i am foo')
    print("foo is running")

3、又有需求

假設現在有100個函數需要增加這個需求,并且后續可能還要對這一百個函數都增加執行前打印日志的需求,怎么辦?還一個個改嗎?

當然不了,這樣會造成大量雷同的代碼,為了減少重復寫代碼,我們可以這樣做,重新定義一個函數:專門處理日志 ,日志處理完之后再執行真正的業務代碼。

def use_logging(func):
    print("%s is running" % func.__name__)
    func()

def bar():
    print('i am bar')

use_logging(bar)
運行結果:
#bar is running
#i am bar

函數use_logging就是裝飾器,它把執行真正業務方法的func包裹在函數里面,看起來像bar被use_logging裝飾了。在這個例子中,函數進入和退出時 ,被稱為一個橫切面(Aspect),這種編程方式被稱為面向切面的編程(Aspect-Oriented Programming)。

通過以上use_logging函數我們增加了日志功能,不管以后有多少函數需要增加日志或者修改日志的格式我們只需要修改use_logging函數,并執行use_logging(被裝飾的函數)就達到了我們想要的效果。

def use_logging(func):
    print("%s is running" % func.__name__)
    return func

@use_logging
def bar():
    print('i am bar')

bar()

三、基礎裝飾器入門

1、裝飾器語法糖

python提供了@符號作為裝飾器的語法糖,使我們更方便的應用裝飾函數;但使用語法糖要求裝飾函數必須return一個函數對象。因此我們將上面的func函數使用內嵌函數包裹并return。

裝飾器相當于執行了裝飾函數use_loggin后又返回被裝飾函數bar,因此bar()被調用的時候相當于執行了兩個函數。等價于use_logging(bar)()

def use_logging(func):
    def _deco():
        print("%s is running" % func.__name__)
        func()
    return _deco

@use_logging
def bar():
    print('i am bar')

bar()

2、對帶參數的函數進行裝飾

現在我們的參數需要傳入兩個參數并計算值,因此我們需要對內層函數進行改動傳入我們的兩個參數a和b,等價于use_logging(bar)(1,2)

def use_logging(func):
    def _deco(a,b):
        print("%s is running" % func.__name__)
        func(a,b)
    return _deco

@use_logging
def bar(a,b):
    print('i am bar:%s'%(a+b))

bar(1,2)

我們裝飾的函數可能參數的個數和類型都不一樣,每一次我們都需要對裝飾器做修改嗎?這樣做當然是不科學的,因此我們使用python的變長參數*args和**kwargs來解決我們的參數問題。

3、函數參數數量不確定

不帶參數裝飾器版本,這個格式適用于不帶參數的裝飾器。

經過以下修改,我們已經適應了各種長度和類型的參數。這個版本的裝飾器可以裝飾任意類型的無參數函數。

def use_logging(func):
    def _deco(*args,**kwargs):
        print("%s is running" % func.__name__)
        func(*args,**kwargs)
    return _deco

@use_logging
def bar(a,b):
    print('i am bar:%s'%(a+b))
@use_logging
def foo(a,b,c):
    print('i am bar:%s'%(a+b+c))

bar(1,2)
foo(1,2,3)

4、裝飾器帶參數

帶參數的裝飾器,這個格式適用于帶參數的裝飾器。

某些情況我們需要讓裝飾器帶上參數,那就需要編寫一個返回一個裝飾器的高階函數,寫出來會更復雜。比如:

#! /usr/bin/env python
# -*- coding:utf-8 -*-
# __author__ = "TKQ"

def use_logging(level):
    def _deco(func):
        def __deco(*args, **kwargs):
            if level == "warn":
                print "%s is running" % func.__name__
            return func(*args, **kwargs)
        return __deco
    return _deco

@use_logging(level="warn")
def bar(a,b):
    print('i am bar:%s'%(a+b))

bar(1,3)

# 等價于use_logging(level="warn")(bar)(1,3)

5、functools.wraps

 使用裝飾器極大地復用了代碼,但是他有一個缺點就是原函數的元信息不見了,比如函數的docstring、__name__、參數列表,先看例子:

def use_logging(func):
    def _deco(*args,**kwargs):
        print("%s is running" % func.__name__)
        func(*args,**kwargs)
    return _deco

@use_logging
def bar():
    print('i am bar')
    print(bar.__name__)

bar()

#bar is running
#i am bar
#_deco
#函數名變為_deco而不是bar,這個情況在使用反射的特性的時候就會造成問題。因此引入了functools.wraps解決這個問題。

 使用functools.wraps:

import functools
def use_logging(func):
    @functools.wraps(func)
    def _deco(*args,**kwargs):
        print("%s is running" % func.__name__)
        func(*args,**kwargs)
    return _deco

@use_logging
def bar():
    print('i am bar')
    print(bar.__name__)


bar()

#result:
#bar is running
#i am bar
#bar  ,這個結果是我們想要的。OK啦!

6、實現帶參數和不帶參數的裝飾器自適應

import functools

def use_logging(arg):
    if callable(arg):#判斷參入的參數是否是函數,不帶參數的裝飾器調用這個分支
        @functools.wraps(arg)
        def _deco(*args,**kwargs):
            print("%s is running" % arg.__name__)
            arg(*args,**kwargs)
        return _deco
    else:#帶參數的裝飾器調用這個分支
        def _deco(func):
            @functools.wraps(func)
            def __deco(*args, **kwargs):
                if arg == "warn":
                    print "warn%s is running" % func.__name__
                return func(*args, **kwargs)
            return __deco
        return _deco


@use_logging("warn")
# @use_logging
def bar():
    print('i am bar')
    print(bar.__name__)

bar()

三、類裝飾器

使用類裝飾器可以實現帶參數裝飾器的效果,但實現的更加優雅簡潔,而且可以通過繼承來靈活的擴展.

1、類裝飾器

class loging(object):
    def __init__(self,level="warn"):
        self.level = level

    def __call__(self,func):
        @functools.wraps(func)
        def _deco(*args, **kwargs):
            if self.level == "warn":
                self.notify(func)
            return func(*args, **kwargs)
        return _deco

    def notify(self,func):
        # logit只打日志,不做別的
        print "%s is running" % func.__name__


@loging(level="warn")#執行__call__方法
def bar(a,b):
    print('i am bar:%s'%(a+b))

bar(1,3)

 2、繼承擴展類裝飾器

class email_loging(Loging):
    '''
    一個loging的實現版本,可以在函數調用時發送email給管理員
    '''
    def __init__(self, email='admin@myproject.com', *args, **kwargs):
        self.email = email
        super(email_loging, self).__init__(*args, **kwargs)

    def notify(self,func):
        # 發送一封email到self.email
        print "%s is running" % func.__name__
        print "sending email to %s" %self.email


@email_loging(level="warn")
def bar(a,b):
    print('i am bar:%s'%(a+b))

bar(1,3)

以上就是python 裝飾器的使用與要點的詳細內容,更多關于python 裝飾器的資料請關注腳本之家其它相關文章!

您可能感興趣的文章:
  • python中有函數重載嗎
  • 在Python中實現函數重載的示例代碼
  • python裝飾器原理源碼示例分析
  • Python Pytest裝飾器@pytest.mark.parametrize詳解
  • 理解python中裝飾器的作用
  • 詳解Python裝飾器 給你的咖啡加點料
  • 如何正確理解python裝飾器
  • 如何利用飾器實現 Python 函數重載

標簽:宿遷 駐馬店 常州 江蘇 成都 蘭州 六盤水 山東

巨人網絡通訊聲明:本文標題《python 裝飾器的使用與要點》,本文關鍵詞  python,裝飾,器,的,使用,與,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《python 裝飾器的使用與要點》相關的同類信息!
  • 本頁收集關于python 裝飾器的使用與要點的相關信息資訊供網民參考!
  • 推薦文章
    主站蜘蛛池模板: 双峰县| 北安市| 阿拉善盟| 黄冈市| 虎林市| 武邑县| 凤庆县| 涡阳县| 扎兰屯市| 嘉峪关市| 屯留县| 鄱阳县| 措美县| 昌宁县| 壤塘县| 博爱县| 织金县| 龙泉市| 富裕县| 会泽县| 房山区| 新田县| 车致| 眉山市| 苏尼特右旗| 宁明县| 佛教| 台南市| 桑植县| 永德县| 时尚| 宁南县| 云浮市| 蚌埠市| 巴林右旗| 灵丘县| 志丹县| 正宁县| 绥棱县| 池州市| 天气|