深入理解Python函數(shù),一切皆對象
把函數(shù)賦值給變量
def say(text):
print(text)
speak = say
speak('hello') # hello
del say
say('hello') # NameError: name 'say' is not defined
speak('hello') # hello
speak 只是這個函數(shù)對象的另一個名字,也就是說你可以刪除原來的名字(say),仍然可以通過 speak 調(diào)用這個函數(shù)。這就像普通的變量賦值一樣。請看下圖了解。
函數(shù)作為變量,存儲到數(shù)據(jù)結(jié)構(gòu)
正如我們在第一節(jié)中了解到的,函數(shù)是 Python 中的對象,我們可以將它們存儲在數(shù)據(jù)結(jié)構(gòu)中,就像任何其他對象一樣。要訪問存儲在其中的函數(shù)對象,假設(shè)列表的工作方式如下:
def say(text):
print(text)
funcs = [say, str.lower, str.upper]
for func in funcs:
print(func, "執(zhí)行返回值:", func("Hello"))
# 運(yùn)行結(jié)果:
# Hello
# <function say at 0x7f9b880c6320> 執(zhí)行返回值:None
# <method 'lower' of 'str' objects> 執(zhí)行返回值:hello
# <method 'upper' of 'str' objects> 執(zhí)行返回值:HELLO
函數(shù)作為參數(shù)傳遞
第一次聽到這個詞,你會覺得很奇怪,但是你可以確定,函數(shù)也是一個對象,可以作為參數(shù)傳遞給另一個函數(shù)。
def sayUpper(text):
print(text.upper())
def sayLower(text):
print(text.lower())
def speak(text, func):
func(text)
speak('Hello', sayUpper) # HELLO
speak('Hello', sayLower) # hello
上面的例子我們定義了兩個函數(shù),sayUpper 和 sayLower,然后調(diào)用 speak 函數(shù),將他們作為參數(shù)傳遞給 speak函數(shù)。
函數(shù)作為返回值
函數(shù)可以作為返回值,這個返回值就是一個函數(shù)。
def speaker(volume):
def quiet(text):
return text.lower()
def loud(text):
return text.upper()
if volume < 20:
return quiet
else:
return loud
s = speaker(10)
print(s('Hello')) # hello
S = speaker(30)
print(S('Hello')) # HELLO
上面的例子定義了一個函數(shù) speaker,它接受一個參數(shù) volume,如果 volume 小于 20,返回一個函數(shù) quiet,否則返回一個函數(shù) loud。執(zhí)行 speaker 函數(shù),我們傳入 10,它將返回一個函數(shù) quiet,執(zhí)行 speaker 函數(shù),我們傳入 30,它將返回一個函數(shù) loud。例子中s、S 變量都是函數(shù),它們都是 speaker 函數(shù)的返回值。
通過上面函數(shù)的性質(zhì):可以理解 python 裝飾器的本質(zhì)是一個函數(shù),它接受一個函數(shù)作為參數(shù),并返回一個函數(shù)。
像執(zhí)行函數(shù)一樣執(zhí)行對象
所有函數(shù)都是對象,但所有對象都不是函數(shù)。但是,可以將對象設(shè)置為可調(diào)用的,這允許將它們視為函數(shù)(在某些情況下)。為此,我們可以使用 __call__ 屬性。
class Subtrack:
def __init__(self, a, b):
self.a = a
self.b = b
def __call__(self, x):
return self.a - self.b - x
X = Subtrack(10, 5)
print(X(2)) # 3
上面的例子定義了一個類 Subtrack,它有兩個屬性a 和 b,并且定義了一個函數(shù) __call__,它可以將對象設(shè)置為可調(diào)用的。為此,我們可以使用 __call__ 屬性。X 是 Subtrack 類的實例,因為存在__call__ 函數(shù),它可以像函數(shù)一樣被調(diào)用。需要主要并不是所有的類都有 __call__ 屬性。
總結(jié)
通過上面的學(xué)習(xí)你是否更熟悉了 Python 的函數(shù)了?