一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

腳本之家,腳本語言編程技術(shù)及教程分享平臺(tái)!
分類導(dǎo)航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務(wù)器之家 - 腳本之家 - Python - Python函數(shù)裝飾器指南

Python函數(shù)裝飾器指南

2020-10-17 23:23Yujiaao Python

Python 具有強(qiáng)大的功能和富有表現(xiàn)力的語法。我最喜歡的裝飾之一。本文為大家介紹下Python函數(shù)裝飾器的使用方法,有需要的朋友可以參考下

Python 具有強(qiáng)大的功能和富有表現(xiàn)力的語法。我最喜歡的裝飾之一。在設(shè)計(jì)模式的上下文中,裝飾器動(dòng)態(tài)更改方法或類功能,而不必直接使用子類。當(dāng)您需要擴(kuò)展功能,但不想修改原函數(shù)時(shí),這是理想的選擇。我們可以在任何地方實(shí)現(xiàn)裝飾器模式,但是 Python 通過提供更具表現(xiàn)力的功能和語法來促進(jìn)實(shí)現(xiàn)。

在這篇文章中,將討論 Python 的函數(shù)裝飾器,并附帶一些澄清有關(guān)概念的示例。所有示例均適用 Python 2.7,但相同的概念應(yīng)適用于Python 3,但語法有所更改。

本質(zhì)上,裝飾器充當(dāng)包裝器,在目標(biāo)函數(shù)執(zhí)行之前和之后修改代碼的行為,而無需修改函數(shù)本身,從而增強(qiáng)了原始功能,從而對(duì)其進(jìn)行了裝飾。

您需要了解的功能

 

在潛水之前,應(yīng)先弄清一些先決條件。在 Python 中,函數(shù)是一等公民,它們是對(duì)象,這意味著我們可以用它們做很多有用的事情。

將函數(shù)分配給變量

1
2
3
4
5
6
7
def greet(name):
    return "hello "+name
 
greet_someone = greet
print(greet_someone("John"))
 
# 輸出: hello John

在其他函數(shù)中定義函數(shù)

1
2
3
4
5
6
7
8
9
10
def greet(name):
    def get_message():
        return "Hello "
 
    result = get_message()+name
    return result
 
print(greet("John"))
 
# 輸出: Hello John

可以將函數(shù)作為參數(shù)傳遞給其他函數(shù)

1
2
3
4
5
6
7
8
9
10
def greet(name):
   return "Hello " + name
 
def call_func(func):
    other_name = "John"
    return func(other_name) 
 
print(call_func(greet))
 
# 輸出: Hello John

函數(shù)可以返回其他函數(shù)

換句話說, 函數(shù)生成其他函數(shù)。

1
2
3
4
5
6
7
8
9
10
def compose_greet_func():
    def get_message():
        return "Hello there!"
 
    return get_message
 
greet = compose_greet_func()
print(greet())
 
# 輸出: Hello there!

內(nèi)部函數(shù)可以訪問封閉范圍

更通常稱為閉包。在構(gòu)建裝飾器時(shí)會(huì)遇到的一種非常強(qiáng)大的模式。還要注意的另一件事是,Python 只允許對(duì)外部作用域進(jìn)行讀取訪問,而不是賦值。請(qǐng)注意,我們?nèi)绾涡薷纳厦娴氖纠詮膬?nèi)部函數(shù)的封閉范圍中讀取“name” 參數(shù)并返回新函數(shù)。

1
2
3
4
5
6
7
8
9
10
def compose_greet_func(name):
    def get_message():
        return "Hello there "+name+"!"
 
    return get_message
 
greet = compose_greet_func("John")
print(greet())
 
# 輸出: Hello there John!

裝飾者的組成

 

函數(shù)裝飾器只是現(xiàn)有函數(shù)的包裝器。綜上所述,我們可以構(gòu)建一個(gè)裝飾器。在此示例中,我們考慮一個(gè)函數(shù),該函數(shù)通過p標(biāo)簽包裝另一個(gè)函數(shù)的字符串輸出。

1
2
3
4
5
6
7
8
9
10
11
12
13
def get_text(name):
   return "lorem ipsum, {0} dolor sit amet".format(name)
 
def p_decorate(func):
   def func_wrapper(name):
       return "<p>{0}</p>".format(func(name))
   return func_wrapper
 
my_get_text = p_decorate(get_text)
 
print(my_get_text("John"))
 
# 輸出: <p> lorem ipsum, John dolor sit amet</p>

那是我們的第一個(gè)裝飾。一個(gè)將另一個(gè)函數(shù)作為參數(shù)的函數(shù),將生成一個(gè)新函數(shù),以擴(kuò)展原始函數(shù)的功能,并返回生成的函數(shù),以便我們可以在任何地方使用它。要讓 get_text 本身由 p_decorate 裝飾,我們只需將 p_decorate 的結(jié)果再賦值給 get_text 即可。

1
2
3
4
5
get_text = p_decorate(get_text)
 
print(get_text("John"))
 
# 輸出:<p>lorem ipsum, John dolor sit amet</p>

還要注意的另一點(diǎn)是,我們的修飾函數(shù)帶有一個(gè) name 參數(shù)。在裝飾器中我們要做的就是讓 get_text 的包裝傳遞該參數(shù)。

Python的裝飾語法

 

Python通過一些語法糖使創(chuàng)建和使用裝飾器對(duì)程序員來說更干凈,更友好。不必裝飾 get_text,get_text = p_decorator(get_text) 它有一個(gè)捷徑,即在要使用的函數(shù)之前提供裝飾函數(shù)的名稱即可。裝飾器的名稱應(yīng)帶有@符號(hào)。

1
2
3
4
5
6
7
8
9
10
11
12
def p_decorate(func):
   def func_wrapper(name):
       return "<p>{0}</p>".format(func(name))
   return func_wrapper
 
@p_decorate
def get_text(name):
   return "lorem ipsum, {0} dolor sit amet".format(name)
 
print(get_text("John"))
 
# 輸出: <p>lorem ipsum, John dolor sit amet</p>

現(xiàn)在,讓我們考慮我們要用其他2個(gè)函數(shù)來修飾 get_text 函數(shù),以便在字符串輸出周圍包裝div和strong標(biāo)簽。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def p_decorate(func):
   def func_wrapper(name):
       return "<p>{0}</p>".format(func(name))
   return func_wrapper
 
def strong_decorate(func):
    def func_wrapper(name):
        return "<strong>{0}</strong>".format(func(name))
    return func_wrapper
 
def div_decorate(func):
    def func_wrapper(name):
        return "<div>{0}</div>".format(func(name))
    return func_wrapper

使用基本方法,裝飾 get_text 將遵循以下步驟:

1
get_text = div_decorate(p_decorate(strong_decorate(get_text)))

使用 Python 的裝飾器語法,可以用更具表達(dá)力的功能實(shí)現(xiàn)相同功能。

1
2
3
4
5
6
7
8
9
@div_decorate
@p_decorate
@strong_decorate
def get_text(name):
   return "lorem ipsum, {0} dolor sit amet".format(name)
 
print(get_text("John"))
 
# 輸出: <div><p><strong>lorem ipsum, John dolor sit amet</strong></p></div>

這里要注意的一件事是設(shè)置裝飾器的順序很重要。如果以上示例中的順序不同,則輸出將不同。

裝飾方式

 

在 Python 中,方法是期望其第一個(gè)參數(shù)成為對(duì)當(dāng)前對(duì)象的引用的函數(shù)。我們可以以相同的方式為方法構(gòu)建裝飾器,同時(shí)在包裝函數(shù)中考慮自身

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def p_decorate(func):
   def func_wrapper(self):
       return "<p>{0}</p>".format(func(self))
   return func_wrapper
 
class Person(object):
    def __init__(self):
        self.name = "John"
        self.family = "Doe"
 
    @p_decorate
    def get_fullname(self):
        return self.name+" "+self.family
 
my_person = Person()
print(my_person.get_fullname())

更好的方法是使裝飾器對(duì)函數(shù)和方法都有用。這可以通過將*args 和 **kwargs作為包裝器的參數(shù)來完成,然后它可以接受任意數(shù)量的參數(shù)和關(guān)鍵字參數(shù)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def p_decorate(func):
   def func_wrapper(*args, **kwargs):
       return "<p>{0}</p>".format(func(*args, **kwargs))
   return func_wrapper
 
class Person(object):
    def __init__(self):
        self.name = "John"
        self.family = "Doe"
 
    @p_decorate
    def get_fullname(self):
        return self.name+" "+self.family
 
my_person = Person()
 
print(my_person.get_fullname())

將參數(shù)傳遞給裝飾器

 

回顧上面的示例之前的示例,您會(huì)注意到示例中的裝飾器是多么冗余。3個(gè)裝飾器(div_decorate,p_decorate,strong_decorate)具有相同的功能,但用不同的標(biāo)簽包裝字符串。我們絕對(duì)可以做得更好。為什么不為將標(biāo)簽包裝為字符串的標(biāo)簽提供更通用的實(shí)現(xiàn)?是的,請(qǐng)!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def tags(tag_name):
    def tags_decorator(func):
        def func_wrapper(name):
            return "<{0}>{1}</{0}>".format(tag_name, func(name))
        return func_wrapper
    return tags_decorator
 
@tags("p")
def get_text(name):
    return "Hello "+name
 
print(get_text("John"))
 
# 輸出 <p>Hello John</p>

在這種情況下,需要做更多的工作。裝飾器期望接收一個(gè)函數(shù)作為參數(shù),這就是為什么我們必須構(gòu)建一個(gè)接受這些額外參數(shù)并動(dòng)態(tài)生成裝飾器的原因。在上面的示例tags,是我們的裝飾器生成器。

調(diào)試裝飾功能

 

歸根結(jié)底,裝飾器只是包裝我們的函數(shù),以防調(diào)試出現(xiàn)問題,因?yàn)榘b器函數(shù)不攜帶原始函數(shù)的名稱,模塊和文檔字符串。基于上面的示例,如果我們這樣做:

1
2
print(get_text.__name__)
# 輸出 func_wrapper

期待輸出get_text,然而,get_text__name____doc____module__屬性被包裝(func_wrapper)覆蓋。顯然,我們可以在func_wrapper中重置它們,但是Python提供了一種更好的方法。

救援工具

幸運(yùn)的是,Python(從版本2.5開始)包括functools模塊,其中包含functools.wraps。Wraps 是一個(gè)修飾器,用于將包裝函數(shù)(func_wrapper)的屬性更新為原始函數(shù)(get_text)的屬性。這就像通過@wraps(func)裝飾func_wrapper一樣簡(jiǎn)單。這是更新的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from functools import wraps
 
def tags(tag_name):
    def tags_decorator(func):
        @wraps(func)
        def func_wrapper(name):
            return "<{0}>{1}</{0}>".format(tag_name, func(name))
        return func_wrapper
    return tags_decorator
 
@tags("p")
def get_text(name):
    """returns some text"""
    return "Hello "+name
 
print(get_text.__name__) # get_text
print(get_text.__doc__) # returns some text
print(get_text.__module__) # __main__

您可以從輸出中注意到,get_text 的屬性現(xiàn)在是正確的屬性。

裝飾器在哪里使用

 

相對(duì)于您可以使用裝飾器完成的工作量,本文中的示例非常簡(jiǎn)單。它們可以為您的程序提供如此強(qiáng)大的功能。通常,裝飾器是擴(kuò)展我們不想修改的函數(shù)的行為的理想選擇。有關(guān)有用的裝飾器的大量清單,建議您查看Python Decorator Library

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 亚洲欧美综合在线观看 | 香蕉tv亚洲专区在线观看 | 亚洲精品一区在线观看 | 11 13加污女qq看他下面 | 99久久免费国产精品热 | 亚洲va在线va天堂成人 | 国产伦精一区二区三区视频 | 欧美一级鲁丝片免费看 | 91香蕉国产在线观看免费永久 | 无人区在线观看免费国语完整版 | 欧美亚洲国产一区二区三区 | 精品牛牛影视久久精品 | 日本视频免费在线观看 | 亚洲精品福利一区二区在线观看 | 亚洲国产成人综合 | 丝瓜视频看污片 | 色综合天天综合中文网 | 无人在线高清免费看 | 国产九九在线 | 国产精品成人扳一级aa毛片 | 国产在线98福利播放视频免费 | 男人的j伸到女人的屁股眼 男人吃奶动态图 | a一级一级 | 日韩欧美在线观看综合网另类 | 奇米网在线 | 国产精品俺来也在线观看了 | 亚洲国产cao | jm漫天堂破解版 | 国产精品亚洲一区二区 | 国产一区二区视频在线观看 | 女人张开腿让男人桶视频免费大全 | 日韩欧美中文字幕一区二区三区 | caoporen在线视频入口 | 免费高清资源黄网站在线观看 | 国产成人99精品免费观看 | 国产手机在线αⅴ片无码观看 | 免费毛片 | 色欲都市| 激情婷婷成人亚洲综合 | 涩色网站 | 亚洲欧美日韩精品久久亚洲区 |