python函式程式設計 返回函式 匿名函式 裝飾器 偏函式

流浪德意志發表於2020-11-04

返回函式

函式的返回物件可以是一個函式,返回時不立即執行,而是呼叫返回物件的時候再執行

def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return sum
>>> f1 = lazy_sum(1, 3, 5, 7, 9)
>>> f2 = lazy_sum(1, 3, 5, 7, 9)
>>> f1==f2
False

lazy_sum返回函式sum時,相關引數和變數都儲存在返回的函式中,稱為閉包Closure.

閉包中儘量避免引用迴圈變數,否則可能出現問題

def count():
    fs = []
    for i in range(1, 4):
        def f():
             return i*i
        fs.append(f)
    return fs

f1, f2, f3 = count()
>>> f1()
9
>>> f2()
9
>>> f3()
9

#解決辦法 是另外定義一個函式 固定住引數
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)立刻被執行,因此i的當前值被傳入f()
    return fs
>>> f1, f2, f3 = count()
>>> f1()
1
>>> f2()
4
>>> f3()
9
#
def createCounter():
    num = 0
    def counter():
        nonlocal num
        num=num+1
        return num
    return counter
# 測試:
counterA = createCounter()
print(counterA(), counterA(), counterA(), counterA(), counterA()) # 1 2 3 4 5
counterB = createCounter()
if [counterB(), counterB(), counterB(), counterB()] == [1, 2, 3, 4]:
    print('測試通過!')
else:
    print('測試失敗!')

利用閉包返回一個計數器函式,每次呼叫它返回遞增整數;

nonlocal 表示全域性變數

匿名函式

匿名函式只有一個表示式,不必擔心函式名稱衝突,直接呼叫;lambda x, x表示引數;

>>> list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
[1, 4, 9, 16, 25, 36, 49, 64, 81]

L = list(filter(lambda n: n % 2 == 1, range(1, 20)))
print(L)#列印奇數
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

裝飾器Decorator

def log(func):
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper
#@語法,把decorator置於函式的定義處
@log
def now():
    print('2015-3-25')

>>> now()
call now():
2015-3-25

wrapper()函式的引數定義是(*args, **kw),因此,wrapper()函式可以接受任意引數的呼叫。在wrapper()函式內,首先列印日誌,再緊接著呼叫原始函式。

更復雜的用法:

def log(text):
    def decorator(func):
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator

#__name__等屬性複製到wrapper()
import functools
def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper

設計decorator,它可作用於任何函式上,並列印該函式的執行時間: 

import time, functools
def metric(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        s = time.time()
        x = func(*args, **kw)
        e = time.time()
        print('%s executed in %s ms' % (func.__name__, (e-s)*1000.0))
        return x
    return wrapper
# 測試
@metric
def fast(x, y):
    time.sleep(0.0012)
    return x + y;

@metric
def slow(x, y, z):
    time.sleep(0.1234)
    return x * y * z;

f = fast(11, 22)
s = slow(11, 22, 33)
if f != 33:
    print('測試失敗!')
elif s != 7986:
    print('測試失敗!')

偏函式

functools.partial的作用就是,把一個函式的某些引數給固定住(也就是設定預設值),返回一個新的函式,呼叫這個新函式會更簡單。

>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85

參考來源:https://www.liaoxuefeng.com/wiki/1016959663602400/1017454145929440

相關文章