溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Python函數(shù)、遞歸和閉包如何用

發(fā)布時(shí)間:2023-05-11 10:37:34 來(lái)源:億速云 閱讀:103 作者:zzz 欄目:編程語(yǔ)言

這篇文章主要介紹“Python函數(shù)、遞歸和閉包如何用”,在日常操作中,相信很多人在Python函數(shù)、遞歸和閉包如何用問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”Python函數(shù)、遞歸和閉包如何用”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

重新認(rèn)識(shí)函數(shù)

讓我們看一個(gè)函數(shù)的簡(jiǎn)單示例,以確保我們?cè)谕痪S度。

def cheer(volume=None):
    if volume is None:
        print("yay.")
    elif volume == "Louder!":
        print("yay!")
    elif volume == "LOUDER!":
        print("*deep breath*")
        print("yay!")


cheer()  # prints "yay."
cheer("Louder!")  # prints "yay!"
cheer("LOUDER!")  # prints "*deep breath* ...yay!"

這里沒(méi)有什么令人驚訝的。函數(shù)cheer()接受單個(gè)參數(shù)volume。如果我們不為volume傳遞參數(shù),它將默認(rèn)為None。

什么是函數(shù)式編程?

我們這些來(lái)自面向?qū)ο缶幊陶Z(yǔ)言的人已經(jīng)學(xué)會(huì)了從類和對(duì)象的角度來(lái)思考一切。數(shù)據(jù)被組織成對(duì)象,以及負(fù)責(zé)訪問(wèn)和修改該數(shù)據(jù)的函數(shù)。有時(shí)這可行,但有時(shí),類開始感覺(jué)像太多模板。

函數(shù)式編程幾乎與此相反。我們圍繞函數(shù)進(jìn)行組織,我們通過(guò)這些函數(shù)傳遞數(shù)據(jù)。我們必須遵守一些規(guī)則:

  • 函數(shù)應(yīng)該只接受輸入,只產(chǎn)生輸出。

  • 函數(shù)不應(yīng)該有副作用;他們不應(yīng)該修改任何外部的東西。

  • 函數(shù)應(yīng)該(理想情況下)總是為相同的輸入產(chǎn)生相同的輸出。函數(shù)內(nèi)部不應(yīng)該有會(huì)破壞這種模式的狀態(tài)。

現(xiàn)在,在你將所有 Python 代碼重寫為純函數(shù)式之前,停止!不要忘記 Python 的一大優(yōu)點(diǎn)是它是一種多范式語(yǔ)言。你不必選擇一種范式并堅(jiān)持下去;你可以在你的代碼中混合搭配,這樣是最好的。

事實(shí)上,我們已經(jīng)這樣做了!迭代器和生成器都是從函數(shù)式編程中參考而來(lái)的,它們與對(duì)象一起工作得很好。也可以隨意合并 lambda、裝飾器和閉包。這一切都是為了選擇最適合這項(xiàng)工作的工具。

在實(shí)踐中,我們很少能同時(shí)避免副作用。在將函數(shù)式編程的概念應(yīng)用到 Python 代碼中時(shí),你應(yīng)該更多地關(guān)注和慎重考慮副作用,而不是完全避免它們。將它們限制在沒(méi)有更好方法解決問(wèn)題的情況下。這里沒(méi)有硬性規(guī)定可以依靠。你需要培養(yǎng)自己的洞察力。

遞歸

當(dāng)一個(gè)函數(shù)調(diào)用自身時(shí),這稱為遞歸。當(dāng)我們需要重復(fù)函數(shù)的整個(gè)邏輯,但循環(huán)不合適(或者感覺(jué)太混亂)時(shí),這會(huì)很有幫助。

注意:我下面的示例被簡(jiǎn)化以突出遞歸本身。這實(shí)際上并不是遞歸是最佳方法的情況。當(dāng)你需要對(duì)不同的數(shù)據(jù)塊重復(fù)調(diào)用復(fù)雜的語(yǔ)言時(shí),例如當(dāng)你遍歷樹結(jié)構(gòu)時(shí),遞歸 會(huì)更好。

import random
random.seed()


class Villain:

    def __init__(self):
        self.defeated = False

    def confront(self):
        # Roll of the dice.
        if random.randint(0,10) == 10:
            self.defeated = True


def defeat(villain):
    villain.confront()
    if villain.defeated:
        print("Yay!")
        return True
    else:
        print("Keep trying...")
        return defeat(villain)


starlight = Villain()
victory = defeat(starlight)

if victory:
    print("YAY!")

random相關(guān)的東西可能看起來(lái)很新。它與這個(gè)主題并沒(méi)有真正相關(guān),但簡(jiǎn)而言之,我們可以通過(guò)在程序開始時(shí)用隨機(jī)數(shù)生成器生成隨機(jī)數(shù) (random.seed()),然后調(diào)用random.randint(min, max), 函數(shù)里面的minmax定義可能值的包含范圍。

這里邏輯的重要部分是defeat()函數(shù)。只要villain 沒(méi)有被打敗,函數(shù)就會(huì)調(diào)用自己,傳遞villain變量,直到其中一個(gè)函數(shù)調(diào)用返回一個(gè)值。在這種情況下,該值在遞歸調(diào)用堆棧中返回,最終存儲(chǔ)在victory.

不管花多長(zhǎng)時(shí)間*,我們最終都會(huì)打敗那個(gè)villain 。

注意無(wú)限遞歸

遞歸可以是一個(gè)強(qiáng)大的工具,但它也會(huì)帶來(lái)一個(gè)問(wèn)題:如果我們沒(méi)有辦法停下來(lái)怎么辦?

def mirror_pool(lookers):
    reflections = []
    for looker in lookers:
        reflections.append(looker)
    lookers.append(reflections)

    print(f"We have {len(lookers) - 1} duplicates.")

    return mirror_pool(lookers)


duplicates = mirror_pool(["Pinkie Pie"])

顯然,這將永遠(yuǎn)運(yùn)行!一些語(yǔ)言沒(méi)有提供一種干凈的方式來(lái)處理這個(gè)問(wèn)題——函數(shù)只會(huì)無(wú)限遞歸,直到崩潰。

Python 更優(yōu)雅地阻止了這種瘋狂。一旦達(dá)到設(shè)定的遞歸深度(通常為 997-1000 次),它就會(huì)停止整個(gè)程序并引發(fā)錯(cuò)誤:

RecursionError:調(diào)用 Python 對(duì)象時(shí)超出最大遞歸深度

像所有錯(cuò)誤一樣,我們可以在事情失控之前發(fā)現(xiàn)它:

try:
    duplicates = mirror_pool(["Pinkie Pie"])
except RecursionError:
    print("Time to watch paint dry.")

值得慶幸的是,由于我編寫這段代碼的方式,我實(shí)際上不需要做任何特別的事情來(lái)清理 997 個(gè)重復(fù)項(xiàng)。遞歸函數(shù)從未返回,因此duplicates在這種情況下保持未定義。

但是,我們可能希望以另一種方式控制遞歸,因此我們不必使用 try-except來(lái)防止災(zāi)難。在我們的遞歸函數(shù)中,我們可以通過(guò)添加一個(gè)參數(shù)來(lái)跟蹤它被調(diào)用的次數(shù)calls,并在它變得太大時(shí)立即中止。

def mirror_pool(lookers, calls=0):
    calls += 1

    reflections = []
    for looker in lookers:
        reflections.append(looker)
    lookers.append(reflections)

    print(f"We have {len(lookers) - 1} duplicates.")

    if calls < 20:
        lookers = mirror_pool(lookers, calls)

    return lookers


duplicates = mirror_pool(["Pinkie Pie"])
print(f"Grand total: {len(duplicates)} Pinkie Pies!")

我們?nèi)匀恍枰宄绾卧诓粊G失原始數(shù)據(jù)的情況下刪除 20 個(gè)重復(fù)項(xiàng),但至少程序沒(méi)有崩潰。

注意:你可以使用sys.setrecursionlimit(n)覆蓋最大遞歸級(jí)別,其中n是你想要的最大值。

嵌套函數(shù)

有時(shí),我們可能想要一個(gè)函數(shù)中重用一段邏輯,但我們不想通過(guò)創(chuàng)建另一個(gè)函數(shù)來(lái)弄亂我們的代碼。

def use_elements(target):
    elements = ["Honesty", "Kindness", "Laughter",
                "Generosity", "Loyalty", "Magic"]

    def use(element, target):
        print(f"Using Element of {element} on {target}.")

    for element in elements:
        use(element, target)


use_elements("Nightmare Moon")

當(dāng)然,這個(gè)簡(jiǎn)單的例子的問(wèn)題在于它的用處不是很明顯。當(dāng)我們想要將大量邏輯抽象為函數(shù)以實(shí)現(xiàn)可重用性但又不想在主函數(shù)之外定義時(shí),嵌套函數(shù)會(huì)變得很有幫助。如果use()函數(shù)要復(fù)雜得多,并且可能不僅僅是循環(huán)調(diào)用,那么這種設(shè)計(jì)將是合理的。

盡管如此,該示例的簡(jiǎn)單性仍然體現(xiàn)了基本概念。這也帶來(lái)了另一個(gè)困難。你會(huì)注意到,每次我們調(diào)用它時(shí)use(),我們都在傳遞target給內(nèi)部函數(shù),這感覺(jué)毫無(wú)意義。我們不能只使用已經(jīng)在本地范圍內(nèi)的target變量嗎?

事實(shí)上,我們可以:

def use_elements(target):
    elements = ["Honesty", "Kindness", "Laughter",
                "Generosity", "Loyalty", "Magic"]

    def use(element):
        print(f"Using Element of {element} on {target}.")

    for element in elements:
        use(element)


use_elements("Nightmare Moon")

然而,一旦我們嘗試修改該變量,我們就會(huì)遇到麻煩:

def use_elements(target):
    elements = ["Honesty", "Kindness", "Laughter",
                "Generosity", "Loyalty", "Magic"]

    def use(element):
        print(f"Using Element of {element} on {target}.")
        target = "Luna"

    for element in elements:
        use(element)

    print(target)


use_elements("Nightmare Moon")

運(yùn)行該代碼會(huì)引發(fā)錯(cuò)誤:

UnboundLocalError: local variable 'target' referenced before assignment

顯然,它不再認(rèn)識(shí)我們的局部變量target。這是因?yàn)槟J(rèn)情況下,分配給變量時(shí)會(huì)覆蓋封閉范圍中的任何已有相同的變量。因此,該行target == "Luna"試圖創(chuàng)建一個(gè)限制在use()范圍內(nèi)的新變量,并在use_elements()的封閉范圍內(nèi)隱藏已有的target變量。與Python 看到了這一點(diǎn)并假設(shè),因?yàn)槲覀冊(cè)?use()函數(shù)中定義了target,所以對(duì)該變量的所有引用都與該本地名稱相關(guān)。這不是我們想要的!

關(guān)鍵字nonlocal允許我們告訴內(nèi)部函數(shù)我們正在使用來(lái)自封閉局部范圍target變量。

def use_elements(target):
    elements = ["Honesty", "Kindness", "Laughter",
                "Generosity", "Loyalty", "Magic"]

    def use(element):
        nonlocal target
        print(f"Using Element of {element} on {target}.")
        target = "Luna"

    for element in elements:
        use(element)

    print(target)


use_elements("Nightmare Moon")

現(xiàn)在,運(yùn)行結(jié)果,我們看到了打印出來(lái)的值Luna。我們?cè)谶@里的工作完成了!

注意:如果你希望函數(shù)能夠修改定義為全局范圍(在所有函數(shù)之外)的變量,請(qǐng)使用global關(guān)鍵字而不是nonlocal。

閉包

基于嵌套函數(shù)的思想,我們可以創(chuàng)建一個(gè)函數(shù),該函數(shù)實(shí)際上構(gòu)建并返回另一個(gè)函數(shù)(稱為閉包)。

def harvester(pony):
    total_trees = 0

    def applebucking(trees):
        nonlocal pony, total_trees
        total_trees += trees
        print(f"{pony} harvested from {total_trees} trees so far.")

    return applebucking


apple_jack = harvester("Apple Jack")
big_mac = harvester("Big Macintosh")
apple_bloom = harvester("Apple Bloom")

north_orchard = 120
west_orchard = 80  # watch out for fruit bats
east_orchard = 135
south_orchard = 95
near_house = 20

apple_jack(west_orchard)
big_mac(east_orchard)
apple_bloom(near_house)
big_mac(north_orchard)
apple_jack(south_orchard)

在此示例中,applebucking()就是閉包,因?yàn)樗?em>關(guān)閉了非局部變量ponytotal_trees。即使在外部函數(shù)終止后,閉包仍保留對(duì)這些變量的引用。

閉包從harvester()函數(shù)返回,并且可以像任何其他對(duì)象一樣存儲(chǔ)在變量中。正是因?yàn)樗瓣P(guān)閉”了一個(gè)非局部變量,這使得它本身就是一個(gè)閉包。否則,它只是一個(gè)函數(shù)。

在這個(gè)例子中,我使用閉包來(lái)有效地創(chuàng)建帶有狀態(tài)的對(duì)象。換句話說(shuō),每個(gè)收割機(jī)都記得他或她從多少棵樹上收割過(guò)。這種特殊用法并不嚴(yán)格符合函數(shù)式編程,但如果你不想創(chuàng)建一個(gè)完整的類來(lái)存儲(chǔ)一個(gè)函數(shù)的狀態(tài),它會(huì)非常有用!

apple_jack, big_macintosh, 和apple_bloom現(xiàn)在是三個(gè)不同的函數(shù),每個(gè)函數(shù)都有自己獨(dú)立的狀態(tài);他們每個(gè)人都有不同的名字,并記住他們收獲了多少棵樹。在一個(gè)閉包狀態(tài)中發(fā)生的事情對(duì)其他閉包狀態(tài)沒(méi)有影響,他們都是獨(dú)立的個(gè)體。

當(dāng)我們運(yùn)行代碼時(shí),我們看到了這個(gè)狀態(tài):

Apple Jack harvested from 80 trees so far.
Big Macintosh harvested from 135 trees so far.
Apple Bloom harvested from 20 trees so far.
Big Macintosh harvested from 255 trees so far.
Apple Jack harvested from 175 trees so far.
閉包的問(wèn)題

閉包本質(zhì)上是“隱式類”,因?yàn)樗鼈儗⒐δ芗捌涑志眯畔ⅲ顟B(tài))放在同一個(gè)對(duì)象中。然而,閉包有幾個(gè)獨(dú)特的缺點(diǎn):

  • 你不能按原樣訪問(wèn)“成員變量”。在我們的示例中,我永遠(yuǎn)無(wú)法訪問(wèn)閉包apple_jack上的變量total_trees!我只能在閉包自己的代碼的上下文中使用該變量。

  • 關(guān)閉狀態(tài)是完全不透明的。除非你知道閉包是如何編寫的,否則你不知道它記錄了哪些信息。

  • 由于前面兩點(diǎn),根本不可能直接知道閉包何時(shí)具有任何狀態(tài)。

使用閉包時(shí),你需要準(zhǔn)備好處理這些問(wèn)題,以及它們帶來(lái)的所有調(diào)試?yán)щy。我建議在你需要單個(gè)函數(shù)來(lái)存儲(chǔ)調(diào)用之間的少量私有狀態(tài)時(shí)才使用它們,并且僅在代碼中如此有限的時(shí)間段內(nèi)使用它們,以至于編寫整個(gè)類并不合理。(另外,不要忘記生成器和協(xié)程,它們可能更適合許多此類場(chǎng)景。)

閉包仍然可以成為 Python中有用的部分,只要你非常小心地使用它們。

Lambdas

lambda是由單個(gè)表達(dá)式組成的匿名函數(shù)(無(wú)名稱)。

僅此定義就是許多程序員無(wú)法想象他們?yōu)槭裁葱枰粋€(gè)定義的原因。編寫一個(gè)沒(méi)有名稱的函數(shù)有什么意義,基本上使重用完全不切實(shí)際?當(dāng)然,你可以lambda 分配給一個(gè)變量,但此時(shí),你不應(yīng)該剛剛編寫了一個(gè)函數(shù)嗎?

為了理解這一點(diǎn),讓我們先看一個(gè)沒(méi)有lambdas 的例子:

class Element:

    def __init__(self, element, color, pony):
        self.element = element
        self.color = color
        self.pony = pony

    def __repr__(self):
        return f"Element of {self.element} ({self.color}) is attuned to {self.pony}"


elements = [
    Element("Honesty", "Orange", "Apple Jack"),
    Element("Kindness", "Pink", "Fluttershy"),
    Element("Laughter", "Blue", "Pinkie Pie"),
    Element("Generosity", "Violet", "Rarity"),
    Element("Loyalty", "Red", "Rainbow Dash"),
    Element("Magic", "Purple", "Twilight Sparkle")
]


def sort_by_color(element):
    return element.color


elements = sorted(elements, key=sort_by_color)
print(elements)

我希望你注意的主要事情是sort_by_color()函數(shù),我必須編寫該函數(shù)以明確按顏色對(duì)列表中的 Element 對(duì)象進(jìn)行排序。實(shí)際上,這有點(diǎn)煩人,因?yàn)槲以僖膊恍枰莻€(gè)功能了。

這就是 lambdas 的用武之地。我可以刪除整個(gè)函數(shù),并將elements = sorted(...)行更改為:

elements = sorted(elements, key=lambda e: e.color)

使用 lambda 可以讓我準(zhǔn)確地描述我的邏輯我在哪里使用它,而不是在其他任何地方。(這key=部分只是表明我將 lambda 傳遞給sorted()函數(shù)的key的參數(shù)。)

一個(gè) lambda 具有結(jié)構(gòu)lamba <parameters>: <return expression>。它可以收集任意數(shù)量的參數(shù),用逗號(hào)分隔,但它只能有一個(gè)表達(dá)式,其值是隱式返回的。

注意:與常規(guī)函數(shù)不同,Lambda 不支持類型注釋(類型提示)。

如果我想重寫那個(gè) lambda 以按元素的名稱而不是顏色排序,我只需要更改表達(dá)式部分:

elements = sorted(elements, key=lambda e: e.name)

就這么簡(jiǎn)單。

同樣,lambda在需要將帶有單個(gè)表達(dá)式的函數(shù)傳遞給另一個(gè)函數(shù)時(shí)非常有用。這是另一個(gè)示例,這次在 lambda 上使用了更多參數(shù)。

為了設(shè)置這個(gè)示例,讓我們從 Flyer 的類開始,它存儲(chǔ)名稱和最大速度,并返回 Flyer 的隨機(jī)速度。

import random
random.seed()


class Flyer:

    def __init__(self, name, top_speed):
        self.name = name
        self.top_speed = top_speed

    def get_speed(self):
        return random.randint(self.top_speed//2, self.top_speed)

我們希望能夠讓任何給定的 Flyer 對(duì)象執(zhí)行任何飛行技巧,但是將所有這些邏輯放入類本身是不切實(shí)際的……可能有成千上萬(wàn)的飛行技巧和變體!

Lambdas是定義這些技巧的一種方式。我們將首先向該類添加一個(gè)函數(shù),該函數(shù)可以接受函數(shù)作為參數(shù)。我們假設(shè)這個(gè)函數(shù)總是有一個(gè)參數(shù):執(zhí)行技巧的速度。

def perform(self, trick):
        performed = trick(self.get_speed())
        print(f"{self.name} perfomed a {performed}")

要使用它,我們創(chuàng)建一個(gè) Flyer 對(duì)象,然后將函數(shù)傳遞給它的perform()方法。

rd = Flyer("Rainbow Dash", 780)
rd.perform(lambda s: f"barrel-roll at {s} mph.")
rd.perform(lambda s: f"flip at {s} mph.")

因?yàn)?lambda 的邏輯在函數(shù)調(diào)用中,所以更容易看到發(fā)生了什么。

回想一下,你可以將 lambdas 存儲(chǔ)在變量中。當(dāng)你希望代碼如此簡(jiǎn)短但需要一些可重用性時(shí),這實(shí)際上會(huì)很有幫助。例如,假設(shè)我們有另一個(gè) Flyer,我們希望他們兩個(gè)都進(jìn)行barrelroll。

spitfire = Flyer("Spitfire", 650)
barrelroll = lambda s: f"barrel-roll at {s} mph."

spitfire.perform(barrelroll)
rd.perform(barrelroll)

當(dāng)然,我們可以將barrelroll寫成一個(gè)適當(dāng)?shù)膯涡泻瘮?shù),但是通過(guò)這種方式,我們?yōu)樽约汗?jié)省了一些樣板文件。而且,由于在這段代碼之后我們不會(huì)再次使用該邏輯,因此沒(méi)有必要再使用一個(gè)成熟的函數(shù)。

再一次,可讀性很重要。Lambda 非常適合用于簡(jiǎn)短、清晰的邏輯片段,但如果你有更復(fù)雜的事情,你還是應(yīng)該編寫一個(gè)合適的函數(shù)。

裝飾器

假設(shè)我們想要修改任何函數(shù)的行為,而不實(shí)際更改函數(shù)本身。

讓我們從一個(gè)相當(dāng)基本的函數(shù)開始:

def partial_transfiguration(target, combine_with):
    result = f"{target}-{combine_with}"
    print(f"Transfiguring {target} into {result}.")
    return result


target = "frog"
target = partial_transfiguration(target, "orange")
print(f"Target is now a {target}.")

運(yùn)行給我們:

Transfiguring frog into frog-orange.
Target is now a frog-orange.

很簡(jiǎn)單,對(duì)吧。但是,如果我們想為此添加一些額外的宣傳呢?如你所知,我們真的不應(yīng)該將這種邏輯放在我們的partial_transfiguration函數(shù)中。

這就是裝飾器的用武之地。裝飾器“包裝”了函數(shù)周圍的附加邏輯,這樣我們實(shí)際上不會(huì)修改原始函數(shù)本身。這使得代碼更易于維護(hù)。

讓我們從為大張旗鼓創(chuàng)建一個(gè)裝飾器開始。這里的語(yǔ)法一開始可能看起來(lái)有點(diǎn)過(guò)于復(fù)雜,但請(qǐng)放心,我會(huì)詳細(xì)介紹。

import functools


def party_cannon(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print("Waaaaaaaait for it...")
        r = func(*args, **kwargs)
        print("YAAY! *Party cannon explosion*")
        return r

    return wrapper

你可能已經(jīng)認(rèn)識(shí)到wrapper()它實(shí)際上是一個(gè)閉包,它是由我們的party_cannon()函數(shù)創(chuàng)建并返回的。我們傳遞我們正在“裝飾”的函數(shù),func。

然而,我們真的對(duì)我們裝飾的函數(shù)一無(wú)所知!它可能有也可能沒(méi)有參數(shù)。閉包的參數(shù)列表(*args, **kwargs)實(shí)際上可以接受任何數(shù)量的參數(shù),從零到無(wú)窮大。調(diào)用func()時(shí),我們以相同的方式將這些參數(shù)傳遞給func()。

當(dāng)然,如果func()上的參數(shù)列表與通過(guò)裝飾器傳遞給它的參數(shù)之間存在某種不匹配,則會(huì)引發(fā)通常和預(yù)期的錯(cuò)誤(這顯然是一件好事)。

wrapper()內(nèi)部,我們可以隨時(shí)隨地調(diào)用我們的函數(shù)func()。我選擇在打印我的兩條消息之間這樣做。

我不想丟棄func()返回的值,所以我將返回的值分配給r,并確保在裝飾器的末尾用return r.

請(qǐng)注意,對(duì)于在裝飾器中調(diào)用函數(shù)的方式,或者即使調(diào)用它或調(diào)用多少次,實(shí)際上并沒(méi)有硬性規(guī)定。你還可以以任何你認(rèn)為合適的方式處理參數(shù)和返回值。關(guān)鍵是要確保裝飾器實(shí)際上不會(huì)以某種意想不到的方式破壞它裝飾的函數(shù)。

裝飾器前的奇數(shù)行,@functools.wraps(func),實(shí)際上是一個(gè)裝飾器本身。沒(méi)有它,被裝飾的函數(shù)本質(zhì)上會(huì)混淆它自己的身份,弄亂我們對(duì)__doc__(文檔字符串)和__name__.。這個(gè)特殊的裝飾器確保不會(huì)發(fā)生這種情況;被包裝的函數(shù)保留自己的身份,可以從函數(shù)外部以所有常用方式訪問(wèn)。(要使用那個(gè)特殊的裝飾器,我們必須首先import functools。)

現(xiàn)在我們已經(jīng)編寫了party_cannon裝飾器,我們可以使用它來(lái)添加我們想要的partial_transfiguration()函數(shù)。這樣做很簡(jiǎn)單:

@party_cannon
def partial_transfiguration(target, combine_with):
    result = f"{target}-{combine_with}"
    print(f"Transfiguring {target} into {result}.")
    return result

第一行,@party_cannon是我們做出的唯一改變!partial_transfiguration函數(shù)現(xiàn)在已裝飾

注意:你甚至可以將多個(gè)裝飾器堆疊在一起,一個(gè)在下一個(gè)之上。只需確保每個(gè)裝飾器緊接在它所包裝的函數(shù)或裝飾器之前。

我們以前的用法根本沒(méi)有改變:

target = "frog"
target = partial_transfiguration(target, "orange")
print(f"Target is now a {target}.")

然而輸出確實(shí)發(fā)生了變化:

Waaaaaaaait for it...
Transfiguring frog into frog-orange.
YAAY! *Party cannon explosion*
Target is now a frog-orange.

到此,關(guān)于“Python函數(shù)、遞歸和閉包如何用”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI