最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python裝飾器用法實例總結

 更新時間:2018年02月07日 10:30:44   作者:蒼松  
這篇文章主要介紹了Python裝飾器用法,結合實例形式總結分析了Python常用裝飾器的概念、功能、使用方法及相關注意事項,需要的朋友可以參考下

本文實例講述了Python裝飾器用法。分享給大家供大家參考,具體如下:

一、裝飾器是什么

python的裝飾器本質上是一個Python函數(shù),它可以讓其他函數(shù)在不需要做任何代碼變動的前提下增加額外功能,裝飾器的返回值也是一個函數(shù)對象。簡單的說裝飾器就是一個用來返回函數(shù)的函數(shù)。

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

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

二、為什么需要裝飾器

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

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

2、增加需求

現(xiàn)在有一個新的需求,希望可以記錄下函數(shù)的執(zhí)行日志,于是在代碼中添加日志代碼:

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

3、又有需求

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

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

def use_logging(func):
  print("%s is running" % func.__name__)
  func()
def bar():
  print('i am bar')
use_logging(bar)
#result:
#bar is running
#i am bar

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

def use_logging(func):
  print("%s is running" % func.__name__)
  return func
@use_logging
def bar():
  print('i am bar')
bar()

三、基礎裝飾器入門

1、裝飾器語法糖

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

裝飾器相當于執(zhí)行了裝飾函數(shù)use_loggin后又返回被裝飾函數(shù)bar,因此bar()被調用的時候相當于執(zhí)行了兩個函數(shù)。等價于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、對帶參數(shù)的函數(shù)進行裝飾

現(xiàn)在我們的參數(shù)需要傳入兩個參數(shù)并計算值,因此我們需要對內層函數(shù)進行改動傳入我們的兩個參數(shù)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)

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

3、函數(shù)參數(shù)數(shù)量不確定

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

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

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、裝飾器帶參數(shù)

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

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

#! /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

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

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
#函數(shù)名變?yōu)開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、實現(xiàn)帶參數(shù)和不帶參數(shù)的裝飾器自適應

import functools
def use_logging(arg):
  if callable(arg):#判斷參入的參數(shù)是否是函數(shù),不帶參數(shù)的裝飾器調用這個分支
    @functools.wraps(arg)
    def _deco(*args,**kwargs):
      print("%s is running" % arg.__name__)
      arg(*args,**kwargs)
    return _deco
  else:#帶參數(shù)的裝飾器調用這個分支
    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()

三、類裝飾器

使用類裝飾器可以實現(xiàn)帶參數(shù)裝飾器的效果,但實現(xiàn)的更加優(yōu)雅簡潔,而且可以通過繼承來靈活的擴展.

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")#執(zhí)行__call__方法
def bar(a,b):
  print('i am bar:%s'%(a+b))
bar(1,3)

2、繼承擴展類裝飾器

class email_loging(Loging):
  '''
  一個loging的實現(xiàn)版本,可以在函數(shù)調用時發(fā)送email給管理員
  '''
  def __init__(self, email='admin@myproject.com', *args, **kwargs):
    self.email = email
    super(email_loging, self).__init__(*args, **kwargs)
  def notify(self,func):
    # 發(fā)送一封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數(shù)據(jù)結構與算法教程》、《Python Socket編程技巧總結》、《Python函數(shù)使用技巧總結》、《Python字符串操作技巧匯總》及《Python入門與進階經(jīng)典教程

希望本文所述對大家Python程序設計有所幫助。

相關文章

  • python miniWeb框架搭建過程詳解

    python miniWeb框架搭建過程詳解

    這篇文章主要介紹了python miniWeb框架搭建,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-10-10
  • python Tensor和Array對比分析

    python Tensor和Array對比分析

    今天小編就為大家分享一篇python Tensor和Array對比分析,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-01-01
  • 淺析python redis的連接及相關操作

    淺析python redis的連接及相關操作

    Redis是一個開源的使用ANSIC語言編寫、支持網(wǎng)絡、可基于內存亦可持久化的日志型、Key-Value數(shù)據(jù)庫,并提供多種語言的API。這篇文章主要介紹了python redis的連接及相關操作,需要的朋友可以參考下
    2019-11-11
  • 用python打印菱形的實操方法和代碼

    用python打印菱形的實操方法和代碼

    在本篇文章里小編給大家分享了關于用python打印菱形的實操方法和代碼,對此有需要的朋友們可以學習下。
    2019-06-06
  • Django中的DateTimeField和DateField實現(xiàn)

    Django中的DateTimeField和DateField實現(xiàn)

    這篇文章主要介紹了Django中的DateTimeField和DateField實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-02-02
  • python隊列基本操作和多線程隊列

    python隊列基本操作和多線程隊列

    pythonQueue隊列模塊提供了同步線程安全的隊列類,包括FIFO(先入先出)隊列Queue,LIFO(后入先出)隊列LifoQueue,和優(yōu)先級隊列PriorityQueue,這些隊列都實現(xiàn)了鎖原語,能夠在多線程中直接使用,可以使用隊列來實現(xiàn)線程間的同步,下面我們就來看看python隊列基本操作吧
    2022-02-02
  • python爬蟲爬取微博評論案例詳解

    python爬蟲爬取微博評論案例詳解

    這篇文章主要介紹了python爬蟲爬取微博評論,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-03-03
  • 6種將Python代碼打包成exe應用的方式

    6種將Python代碼打包成exe應用的方式

    這篇文章主要給大家介紹了關于6種將Python代碼打包成exe應用的方式,對于很多python的初學者來說,很希望將自己用python寫的.py文件生成exe直接在電腦上運行,需要的朋友可以參考下
    2023-08-08
  • 計算機二級python學習教程(1) 教大家如何學習python

    計算機二級python學習教程(1) 教大家如何學習python

    這篇文章主要為大家詳細介紹了計算機二級python學習教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • Python爬取商家聯(lián)系電話以及各種數(shù)據(jù)的方法

    Python爬取商家聯(lián)系電話以及各種數(shù)據(jù)的方法

    今天小編就為大家分享一篇Python爬取商家聯(lián)系電話以及各種數(shù)據(jù)的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-11-11

最新評論

揭阳市| 云林县| 长垣县| 勐海县| 奇台县| 鄯善县| 定西市| 深州市| 博湖县| 三亚市| 连平县| 信丰县| 焉耆| 宜宾市| 万宁市| 马鞍山市| 双辽市| 波密县| 揭阳市| 冀州市| 遂川县| 安宁市| 湖北省| 深泽县| 新余市| 会理县| 彰武县| 祁阳县| 阜康市| 长子县| 吉林市| 东至县| 青神县| 贞丰县| 夏河县| 乐都县| 塘沽区| 盘山县| 西青区| 昭苏县| 礼泉县|