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

Python學習筆記之裝飾器

 更新時間:2020年08月06日 11:30:02   作者:pxrux  
這篇文章主要介紹了Python 裝飾器的相關(guān)資料,文中講解非常細致,代碼幫助大家更好的理解和學習,感興趣的朋友可以了解下

一. 什么是裝飾器

知乎某大佬如是說:內(nèi)褲可以用來遮羞,但是到了冬天它沒法為我們防風御寒,聰明的人們發(fā)明了長褲,有了長褲后寶寶再也不冷了,裝飾器就像我們這里說的長褲,在不影響內(nèi)褲作用的前提下,給我們的身子提供了保暖的功效。
裝飾器本質(zhì)上是Python函數(shù),可以為已存在的對象添加額外的功能,同時裝飾器還可以抽離出與函數(shù)無關(guān)的重用代碼。具體應用場景如:插入日志、性能測試、事務處理、緩存、權(quán)限校驗等。

換言之

裝飾器不能影響原函數(shù)的功能,裝飾器是獨立出來的函數(shù)。誰調(diào)用它,誰就可以使用它的功能。

二.舉個栗子

add的功能是計算x和y的值,我們稱作功能函數(shù)。
logger的作業(yè)是在執(zhí)行add函數(shù)的同時再打印了其他的信息,這部分的作為add的功能增強,我們稱為裝飾。
在logger里我們可以加入其他類似的功能函數(shù),也能包裝它,可以進行復用。

1.引子

#功能函數(shù)
def add(x,y):
 return x+y

#裝飾函數(shù)
def logger(fn):
 print('frist')
 x = fn(4,5)
 print('second')
 return x 

print(logger(add))

#把函數(shù)add傳給logger ,return x+y
#print('frist')
#print('secend')
# x = fn(4,5) ==> x = 4 y= 5 x= 4+5 = 9 
#return 9 

frist
second
9

2.提取參數(shù)

x,y的參數(shù)都放在logger函數(shù)內(nèi)部了,影響函數(shù)的靈活性,此處我們可以提取出來。

def add(x,y):
 return x + y

def logger(fn,*args,**kwargs):
 print('frist')
 x = fn(*args,**kwargs)
 print('second')
 return x

print(logger(add,1,y=11))

frist
second
12

3.柯里化

def add(x,y):
 return x + y
def logger(fn):
 def wrapper(*args,**kwargs):
  print('begin')
  x = fn(*args,**kwargs)
  print('end')
  return x
 return wrapper


print(logger(add)(5,y=11))

begin
end
16

懵逼ing

以下為個人理解,左邊為非柯里化函數(shù),右邊是柯里化函數(shù)。

柯里化函數(shù)

前面說過柯里化的定義,本來可以一次傳入兩個參數(shù),柯里化之后。只需要傳入一個函數(shù)了。。
左邊傳入add 和 兩個參數(shù)。
右邊的logger(add)是一個函數(shù),只需要傳入兩個參數(shù)。logger(add)是個整體,結(jié)合成一個函數(shù)。當然這樣寫,我們看函數(shù)主題的部分也是不一樣的。
函數(shù)的基礎(chǔ)中說過,函數(shù)的傳參必須和函數(shù)參數(shù)的定義一致。重點分析右邊函數(shù)(柯里化)。
參數(shù)部分:參數(shù)傳入的方式,logger函數(shù)需要傳入個fn,fu的返回值是wrapper函數(shù),wrapper函數(shù)的參數(shù)是(*args,**kwargs)所以此次就需要分兩次傳入?yún)?shù)。
第一次傳入fn,再次傳入wrapper函數(shù)需要的參數(shù)。所以就出現(xiàn)了最下邊的調(diào)用方式。
print(logger(add)(5,y=50))。

返回值部分:右側(cè)的logger函數(shù)是個嵌套函數(shù),logger的返回值是wrapper,內(nèi)層的wrapper函數(shù)返回值是x,x = fn(*args,**kwargs)。fn函數(shù)是最后調(diào)用時候傳入的add函數(shù)。

懵逼 X 2。。。。

def add(x,y):
 return x + y

def logger(fn,*args,**kwargs):  def logger(fn): #參數(shù)剝離
           def newfunction(*args,**kwargs): #新定義一個函數(shù),logger函數(shù)返回也是這個函數(shù)名字
 print('frist')       print('frist')
 x = fn(*args,**kwargs) == >    x = fn(*args,**kwargs)
 print('second')       print('second')
 return x        return x
          return newfunction

print(logger(add,1,y=11))   print(logger(add)(5,y=11)) #兩次傳入?yún)?shù)

效果如下:

def add(x,y):
 return x + y

def logger(fn): #參數(shù)剝離
 def newfunction(*args,**kwargs): #新定義一個函數(shù),logger函數(shù)返回也是這個函數(shù)名字

  print('frist')
  x = fn(*args,**kwargs)
  print('second')
  return x

 return newfunction

print(logger(add)(5,y=11)) #兩次傳入?yún)?shù)

frist
second
16

繼續(xù)懵逼的話就這樣用吧。。。用多了就悟道了。。

4.裝飾器語法糖

#再次變形。。。
def add(x,y):
 return x + y

def logger(fn):
 def wrapper(*args,**kwargs):
  print('begin')
  x = fn(*args,**kwargs)
  print('end')
  return x
 return wrapper

##調(diào)用方法1:
print(logger(add)(x=1111,y=1))

##調(diào)用方法2:
add = logger(add)
print(add(x=11,y=3))

##調(diào)用方法3: python給我們的語法糖 

@logger # 說明下邊的函數(shù),add 其實是 add = logger(add)
def add(x,y):
 return x + y


print(add(45,40))

begin
end
1112
begin
end
14
begin
end
85

三.復雜的栗子

import datetime
import time 

def logger(fn):
 def warp(*arges,**kwarges):
  print("arges={},kwarges={}".format(arges,kwarges)) #打印函數(shù)的兩個參數(shù)
  start = datetime.datetime.now() #獲取函數(shù)運行的開始時間
  ret = fn(*arges,**kwarges) #傳入兩個參數(shù),調(diào)用add函數(shù) 此處有個return的值,需要一層一層的返回出去

  duratime = datetime.datetime.now() - start #獲得函數(shù)的運行時間
  print("function {} took {}s".format(fn.__name__,duratime.total_seconds())) #打印函數(shù)的運行時間

  return ret #返回fn的結(jié)果 ,fn = x+y ==> 返回x+y的值。 x = 4 y= 11 ==> return 11
 return warp #返回warp的 return ==> ret 的return ==> return 11 函數(shù)的最終結(jié)果為11 

@logger
def add(x,y):
 print("oooooook")
 time.sleep(1.5)
 return x+y

print(add(4,y=11))

#如果充分理解了每個小部件,這個簡單的完整版本也是很好理解的了。
#1,logger是個裝飾器,而且使用了柯里化技術(shù)
#2,add 傳參給logger的fn 形參,add(4,y=5)的兩個參數(shù)傳入給warp函數(shù)的兩個形參
#
#
arges=(4,),kwarges={'y': 11}
oooooook
function add took 1.5017s
15

再次翻譯

import datetime
import time 

#####################################裝飾開始############################################
def logger(fn): #拿到函數(shù)名稱
 def warp(*arges,**kwarges): #拿到函數(shù)帶過來的參數(shù)開始裝飾
  print("arges={},kwarges={}".format(arges,kwarges)) #來試試打印兩個參數(shù)
  start = datetime.datetime.now() #
  ret = fn(*arges,**kwarges) # 此處調(diào)用add函數(shù)。開始執(zhí)行函數(shù),發(fā)現(xiàn)return語句。。ret的結(jié)果就是return。 

  duratime = datetime.datetime.now() - start #
  print("function {} took {}s".format(fn.__name__,duratime.total_seconds()))

  return ret #加工完成開始返回。warp的返回值是ret ,ret的返回值是 add函數(shù)的執(zhí)行結(jié)果(原函數(shù)的功能完整的保留了) 
 return warp # logger的返回結(jié)果是warp,warp的返回值是ret ,ret的返回值是 add函數(shù)的執(zhí)行結(jié)果(原函數(shù)的功能完整的保留了) 

#####################################裝飾完成############################################

@logger #裝飾工廠
######add是需要被裝飾的函數(shù),當你有這個想法的事情,其實事情已經(jīng)開始發(fā)生了。
def add(x,y): # 此時add = logger(add) 此處前面的@logger標記就是想要讓logger裝飾器像一個工廠一樣對add函數(shù)進行加工。
 print("oooooook")
 time.sleep(1.5)
 return x+y

print(add(4,y=11))
arges=(4,),kwarges={'y': 11}
oooooook
function add took 1.501604s
15

四.帶參裝飾器

1. 文檔字符串

我們約定,在python函數(shù)的第一行需要對函數(shù)進行說明,使用三引號表示。
如果是英文說明,慣例首字母大寫,第一行寫概述,空一行,第三行寫詳細描述。
如果函數(shù)中有文檔字符串,默認會放在函數(shù)的doc屬性中,可以直接訪問。

def add(x,y):
 """This is a function of addition"""
 a = x+y
 return x + y

print("function name is {}
function doc = {}

".format(add.__name__, add.__doc__))
print(help(add))
function name is add
function doc = This is a function of addition


Help on function add in module __main__:

add(x, y)
 This is a function of addition

None

2. 前面裝飾器的副作用

前面裝飾器基本上已經(jīng)可以完成對函數(shù)進行加強的功能了,但是還有些瑕疵。比如原來函數(shù)的原屬性已經(jīng)被替換為裝飾器的屬性了。如下:

def add(x,y):
 return x + y

def logger(fn):
 "This is logger doc"
 def wrapper(*args,**kwargs):
  "This is wrapper doc"
  print('begin')
  x = fn(*args,**kwargs)
  print('end')
  return x
 return wrapper


@logger # add = logger(add)
def add(x,y):
 "This is add doc "
 print("name = {}
doc = {}".format(add.__name__,add.__doc__))
 return x + y


print(add(45,40))

#可以看出來add被裝飾出來的函數(shù)(新的add)的屬性已經(jīng)全部改變了。

begin
name = wrapper
doc = This is wrapper doc
end
85

3. 解決方案一

三個函數(shù):

第一個:copy原函數(shù)的屬性 copy_properties
第二個:裝飾器 logger
第三個:功能函數(shù) add

def copy_properties(src, dst): # 把src的相關(guān)屬性賦值給dst (fn,wrap)
 dst.__name__ = src.__name__
 dst.__doc__ = src.__doc__


def logger(fn):
 """'This is a function of logger'"""
 def wrap(*arges,**kwarges): # 
  """'This is a function of wrap'"""
  print('<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>')
  x = fn(*arges,**kwarges)
  #print("name={}
doc={}".format(add.__name__,add.__doc__))
  print('<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>') 
  return x 
 copy_properties(fn,wrap) #思考1:為什么放在這個位置調(diào)用
 return wrap

@logger
def add(x,y):
  """'This is a function of add'"""
  print("name={}
doc={}".format(add.__name__,add.__doc__))
  return x+y


print(add(4,6))

<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>
name=add
doc='This is a function of add'
<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>-<>
10

4. 解決方案二

但凡使用裝飾器都會出現(xiàn)屬性的這個問題,為什么不把copy_properties也做成裝飾器呢?

三個函數(shù):

第一個:copy原函數(shù)的裝飾器 copy_properties1
第二個:裝飾器 logger
第三個:功能函數(shù) add

def copy_properties(src, dst): # 把src的相關(guān)屬性賦值給dst (fn,wrap)
 dst.__name__ = src.__name__
 dst.__doc__ = src.__doc__

#利用前面的知識我們可以對copy_properties輕松進行變形
def copy_properties1(src): # 把src的相關(guān)屬性賦值給dst (fn,wrap) 
 def _copy(dst):
  dst.__name__ = src.__name__
  dst.__doc__ = src.__doc__
  return dst 
 return _copy

帶參裝飾器:

def logger(fn): 
 """'This is a function of logger'"""
 @copy_properties1(fn) #wrap = copy_properties(fn)(wrap) 
 #== > 柯里化 兩次傳入?yún)?shù) src = fn , dst = wrap 新的wrap函數(shù)的屬性已經(jīng)替換為原函數(shù)的。

 def wrap(*arges,**kwarges): #wrap = copy_properties(fn)(wrap)(*arges,**kwarges)  
  """'This is a function of wrap'"""
  print('>->->->->->->->->->->->->->->->->->->->->->->->->->')
  x = fn(*arges,**kwarges)
  print('<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<')
  return x 

 return wrap

@logger #add =logger(add)
def add(x,y):
  """'This is a function of add'"""
  print("name={}
doc={}".format(add.__name__,add.__doc__))
  return x+y



print(add(4,11))

以上就是詳解Python 裝飾器的詳細內(nèi)容,更多關(guān)于Python 裝飾器的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • PyTorch一小時掌握之圖像識別實戰(zhàn)篇

    PyTorch一小時掌握之圖像識別實戰(zhàn)篇

    這篇文章主要介紹了PyTorch一小時掌握之圖像識別實戰(zhàn)篇,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • Python中單元測試的快速入門指南

    Python中單元測試的快速入門指南

    在這篇文章中,我們會深入探討Python單元測試的各個方面,包括它的基本概念、基礎(chǔ)知識、實踐方法、高級話題,感興趣的小伙伴可以跟隨小編一起學習一下
    2023-07-07
  • python3處理含有中文的url方法

    python3處理含有中文的url方法

    今天小編就為大家分享一篇python3處理含有中文的url方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • python制作websocket服務器實例分享

    python制作websocket服務器實例分享

    websocket是一個瀏覽器和服務器通信的新的協(xié)議,websocket則和一般的socket一樣,使得瀏覽器和服務器建立了一個雙工的通道。今天我們就來詳細探討下使用Python實現(xiàn)websocket服務器的具體方法
    2016-11-11
  • Python全局變量操作詳解

    Python全局變量操作詳解

    這篇文章主要介紹了Python全局變量操作詳解,本文總結(jié)了兩種使用全局變量的方式,需要的朋友可以參考下
    2015-04-04
  • pygame可視化幸運大轉(zhuǎn)盤實現(xiàn)

    pygame可視化幸運大轉(zhuǎn)盤實現(xiàn)

    這篇文章主要介紹了pygame可視化幸運大轉(zhuǎn)盤實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04
  • Python從PDF中提取文本的方法效率總結(jié)

    Python從PDF中提取文本的方法效率總結(jié)

    日常工作中我們經(jīng)常會用到pdf格式的文件,大多數(shù)情況下是瀏覽或者編輯pdf信息,但有時候需要提取pdf中的文本,這篇文章主要給大家總結(jié)介紹了關(guān)于Python從PDF中提取文本的方法效率,需要的朋友可以參考下
    2023-09-09
  • python ETL工具 pyetl

    python ETL工具 pyetl

    pyetl是一個純python開發(fā)的ETL框架, 相比sqoop, datax 之類的ETL工具,pyetl可以對每個字段添加udf函數(shù),使得數(shù)據(jù)轉(zhuǎn)換過程更加靈活,相比專業(yè)ETL工具pyetl更輕量,純python代碼操作,更加符合開發(fā)人員習慣。這篇文章主要介紹了python ETL工具 pyetl,需要的朋友參考下
    2020-06-06
  • Python中出現(xiàn)"No?module?named?'requests'"的圖文解決辦法

    Python中出現(xiàn)"No?module?named?'requests'"

    這篇文章主要給大家介紹了關(guān)于Python中出現(xiàn)"No?module?named?'requests'"的解決辦法,"No?module?named?requests"是Python報錯提示,意味著你在使用某個Python程序或腳本時,沒有找到名為requests的模塊,需要的朋友可以參考下
    2023-11-11
  • python使用watchdog實現(xiàn)文件資源監(jiān)控

    python使用watchdog實現(xiàn)文件資源監(jiān)控

    watchdog 支持跨平臺文件資源監(jiān)控,可以檢測指定文件夾下文件及文件夾變動,下面我們來看看Python如何使用watchdog實現(xiàn)文件資源監(jiān)控吧
    2025-01-01

最新評論

建瓯市| 育儿| 治多县| 石首市| 安顺市| 宁德市| 北宁市| 安吉县| 成都市| 东乡县| 厦门市| 慈溪市| 沙雅县| 晋江市| 偃师市| 柞水县| 鄯善县| 万宁市| 盐源县| 宁化县| 陈巴尔虎旗| 奈曼旗| 报价| 凤凰县| 水城县| 宜都市| 山东省| 万年县| 承德市| 临城县| 嵊州市| 天水市| 洞头县| 芦山县| 岳阳市| 砀山县| 长治县| 南安市| 威信县| 青浦区| 安化县|