【Python】返回函數(shù)/匿名函數(shù)/裝飾器/偏函數(shù)

返回函數(shù)

函數(shù)作為返回值。

def A(n):
    def a():
        return n
    return a

調用A時,返回函數(shù)a,調用a時,返回值

>>> A(2)
<function A.<locals>.a at 0x1085fcea0>
>>> A(2)()
2

閉包
在函數(shù)里又定義了新函數(shù),內部函數(shù)可以引用外部函數(shù)的參數(shù)和局部變量,當外部函數(shù)返回內部函數(shù)時,相關參數(shù)和變量都存在返回的函數(shù)中

調用A()時,每次調用都會返回一個新的函數(shù),即使傳入相同的參數(shù)

>>> A(2)==A(2)
False

返回的函數(shù)并沒有立刻執(zhí)行,而是直到調用了fs()才執(zhí)行

def count():
    fs = []
    for i in range(1, 4):
        def f():
             return i*i
        fs.append(f)
    return fs
#此時 調用count函數(shù), count()返回三個函數(shù)
>>> count
<function count at 0x108621048>
>>> count()
[<function count.<locals>.f at 0x1085f51e0>, <function count.<locals>.f at 0x108621158>, <function count.<locals>.f at 0x1086210d0>]
#看看調用每一個函數(shù)返回什么值
>>> [x() for x in count()]
[9, 9, 9]

都是9~返回一個函數(shù)時,牢記該函數(shù)并未執(zhí)行,返回函數(shù)中不要引用任何可能會變化的變量。

def count():
    def f(j):
        def g():
            return j*j
        return g
    fs = []
    for i in range(1, 4):
        fs.append(f(i)) # f(i)立刻被執(zhí)行,因此i的當前值被傳入f()
    return fs
>>> [x() for x in count()]
[1, 4, 9]

fs.append(f) f最后才被計算
fs.append(f(i)) f(i)立刻被執(zhí)行,因此i的當前值被傳入f()


匿名函數(shù)

lambda 函數(shù)參數(shù):函數(shù)式
匿名函數(shù)有個限制,就是只能有一個表達式,不用寫return,返回值就是該表達式的結果。幾個常見用法:

  1. 高階函數(shù)
>>> list(map(lambda x: x * x, [1, 2, 3]))
[1, 4, 9]
  1. 賦值給變量再通過變量調用
>>> f = lambda x: x * x
>>> f
<function <lambda> at 0x101c6ef28>
>>> f(5)
25
  1. 作為返回值返回
def build(x, y):
    return lambda: x * x + y * y

裝飾器

在代碼運行期間動態(tài)增加功能的方式,稱之為“裝飾器”(Decorator)
decorator就是一個返回函數(shù)的高階函數(shù),接受一個函數(shù)作為參數(shù),并返回一個函數(shù)。

def log(func):
    def wrapper():
        print('call %s():' % func.__name__)
        return func()
    return wrapper
  • 傳入一個函數(shù)func,返回一個函數(shù)wrapper, wrapper就是裝修后的func。網(wǎng)上有人討論說不需要兩層,一層就可以了,其實不行,因為一層會直接print后返回函數(shù)。我們要的是先拿到這個裝飾器,是個把print含在里面的函數(shù)。
  • 在這個例子中,使用方法:
    func=log(func)等價于@log加在 func()函數(shù)定義處前
    這時func成了wrapper,這時調用func()時,返回print以及原func()
@log
def now():
   print('2015-3-25')
#相當于
now = log(now)

要自定義那個"call:"可以再嵌套一層(外面那層是為了注入里層變量text)

def log(text):
    def decorator(func):
        def wrapper():
            print('%s %s():' % (text, func.__name__))
            return func()
        return wrapper
    return decorator
@log('execute')
def now():
    print('2015-3-25')
#相當于
now = log('execute')(now)

但是經過裝飾后, func.__name__現(xiàn)在變成了 'wrapper'而不是'func'了,如下

>>> now.__name__
'wrapper'

因為now現(xiàn)在是log(now) 也就是wrapper
所以應該需要wrapper.__name__ = func.__name_這樣一個過程,或者交給functools.wraps

import functools
def log(func):
    @functools.wraps(func)
    def wrapper():
        print('call %s():' % func.__name__)
        return func()
    return wrapper

練習

請編寫一個decorator,能在函數(shù)調用的前后打印出'begin call'和'end call'的日志。

import functools
def log(func):   
    @functools.wraps(func) 
    def wrapper():
        print('begin call')
        func()
        print('end call')
        return func()
    return wrapper
@log
def now():
    print(123)
>>> now()
begin call
123
end call
123

咋辦呢,難道我就return None?這樣豈不是破壞了原來的func函數(shù)

思考

關于能否寫出一個@log的decorator,使它既支持log又支持log()

Opera2952162625 created at 4-8 17:21, Last updated at 4-8 17:21
這個問題的本質是
對于@log而言,以now()函數(shù)為例,變成now=log(now)
對于@log(text)而言,變成now=log(text)(now)
如何使得在函數(shù)log()中能夠檢測到這種區(qū)別是解決問題的關鍵
評論區(qū)中有使用到callable來判斷@log(text)中的text是否為可調用的對象來區(qū)分此問題,顯然將問題的本質理解成了如下:
log()函數(shù)中傳入的是變量如果不是函數(shù)則使用的是@log(text),如果是函數(shù)則使用的是@log
顯然是不對的,如果@log(text)中參數(shù)text就是函數(shù)呢?
在函數(shù)里面去判斷(調用該函數(shù)的語句的執(zhí)行方案),我覺得應該是不能夠寫出來的


偏函數(shù)

偏函數(shù)就是改變一個函數(shù)的默認參數(shù)后作為一個新函數(shù)
functools.partial幫助我們快捷創(chuàng)建一個偏函數(shù)

>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 匿名函數(shù): lambda 不需要顯式地定義函數(shù),直接傳入匿名函數(shù)更方便。 關鍵字lambda表示匿名函數(shù),冒號前面...
    MJXH閱讀 546評論 0 0
  • 匿名函數(shù) 1)匿名函數(shù)有個限制,就是只能有一個表達式,不用寫return,返回值就是該表達式的結果。 2)因為沒有...
    木凜閱讀 487評論 0 0
  • 函數(shù)式編程就是一種抽象程度很高的編程范式,純粹的函數(shù)式編程語言編寫的函數(shù)沒有變量,因此,任意一個函數(shù),只要輸入是確...
    齊天大圣李圣杰閱讀 1,632評論 0 2
  • Python進階框架 希望大家喜歡,點贊哦首先感謝廖雪峰老師對于該課程的講解 一、函數(shù)式編程 1.1 函數(shù)式編程簡...
    Gaolex閱讀 5,985評論 6 53
  • 一盞燈 一杯茶 一個人 一本書 夜如瀾 寫不出故事的我 心似夢 沉浸于每一個故事里
    伊春雪閱讀 192評論 2 7

友情鏈接更多精彩內容