程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python進階系列(四)

編輯:Python

目錄

從函數中返回函數

將函數作為參數傳給另一個函數

你的第一個裝飾器


從函數中返回函數

其實並不需要在一個函數裡去執行另一個函數,我們也可以將其作為輸出返回出來:

def hi(name="yasoob"):
    def greet():
        return "now you are in the greet() function"
    def welcome():
        return "now you are in the welcome() function"
    if name == "yasoob":
        return greet
    else:
        return welcome
a = hi()
print(a)
#outputs: <function greet at 0x7f2143c01500>
#上面清晰地展示了`a`現在指向到hi()函數中的greet()函數
#現在試試這個
print(a())
#outputs: now you are in the greet() function

再次看看這個代碼。在if/else語句中我們返回greet和welcome,而不是greet()和welcome()。為什麼那樣?這是因為當你把一對小括號放在後面,這個函數就會執行;然而如果你不放括號在它後面,那它可以被到處傳遞,並且可以賦值給別的變量而不去執行它。

你明白了嗎?讓我再稍微多解釋點細節。

當我們寫下a = hi(),hi()會被執行,而由於name參數默認是yasoob,所以函

數greet被返回了。如果我們把語句改為a = hi(name = "ali"),那麼welcome函數將被返回。我們還可以打印出hi()(),這會輸出now you are in the greet() function

將函數作為參數傳給另一個函數

def hi():
    return "hi yasoob!"
def doSomethingBeforeHi(func):
    print("I am doing some boring work before executing hi()")
    print(func())
doSomethingBeforeHi(hi)
#outputs:I am doing some boring work before executing hi()
#        hi yasoob!

現在你已經具備所有必需知識,來進一步學習裝飾器真正是什麼了。裝飾器讓你在一個函數的前後去執行代碼。

你的第一個裝飾器

在上一個例子裡,其實我們已經創建了一個裝飾器!現在我們修改下上一個裝飾器,並編寫一個稍微更有用點的程序:

def a_new_decorator(a_func):
    def wrapTheFunction():
        print("I am doing some boring work before executing a_func()"       
        a_func()       
        print("I am doing some boring work after executing a_func()"
   
    return wrapTheFunction
def a_function_requiring_decoration():
    print("I am the function which needs some decoration to remove my foul smell")
a_function_requiring_decoration()
#outputs: "I am the function which needs some decoration to remove my foul smell
a_function_requiring_decoration=a_new_decorator(a_function_requiring_decoration)
#now a_function_requiring_decoration is wrapped by wrapTheFunction()
a_function_requiring_decoration()
#outputs:I am doing some boring work before executing a_func()
#        I am the function which needs some decoration to remove my foul smell
#        I am doing some boring work after executing a_func()

你看明白了嗎?我們剛剛應用了之前學習到的原理。這正是python中裝飾器做的事情!它們封裝一個函數,並且用這樣或者那樣的方式來修改它的行為。現在你也許疑惑,我們在代碼裡並沒有使用@符號?那只是一個簡短的方式來生成一個被裝飾的函數。這裡是我們如何使用@來運行之前的代碼:


@a_new_decorator
def a_function_requiring_decoration():
    """Hey you! Decorate me!"""
    print("I am the function which needs some decoration to remove my foul smell")
a_function_requiring_decoration()
#outputs: I am doing some boring work before executing a_func()
#         I am the function which needs some decoration to remove my foul smell
#         I am doing some boring work after executing a_func()
#the @a_new_decorator is just a short way of saying:
a_function_requiring_decoration=a_new_decorator(a_function_requiring_decoration)

希望你現在對Python裝飾器的工作原理有一個基本的理解。如果我們運行如下代碼會存在一個問題:


print(a_function_requiring_decoration.__name__)
# Output: wrapTheFunction

這並不是我們想要的!Ouput輸出應該是“a_function_requiring_decoration”。這裡的函數被warpTheFunction替代了。它重寫了我們函數的名字和注釋文檔(docstring)。幸運的是Python提供給我們一個簡單的函數來解決這個問題,那就是functools.wraps。我們修改上一個例子來使用

functools.wraps:
from functools import wraps
def a_new_decorator(a_func):
    @wraps(a_func)
    def wrapTheFunction():
        print("I am doing some boring work before executing a_func()"
        a_func()
        print("I am doing some boring work after executing a_func()"
    return wrapTheFunction
@a_new_decorator
def a_function_requiring_decoration():
    """Hey yo! Decorate me!"""
    print("I am the function which needs some decoration to remove my foul smell")
print(a_function_requiring_decoration.__name__)
# Output: a_function_requiring_decoration

現在好多了。我們接下來學習裝飾器的一些常用場景。

藍本規范:


from functools import wraps
def decorator_name(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        if not can_run:
            return "Function will not run"
        return f(*args, **kwargs)
    return decorated
@decorator_name
def func():
    return("Function is running")
can_run = True
print(func())
# Output: Function is running
can_run = False
print(func())
# Output: Function will not run

注意:@wraps接受一個函數來進行裝飾,並加入了復制函數名稱、注釋文檔、參數列表等等的功能。這可以讓我們在裝飾器裡面訪問在裝飾之前的函數的屬性。


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved