文章目錄
1 函數是 Python 的對象
1 Python
中一切皆爲對象,函數也不例外。可以將函數分配給變量或存儲在數據結構中。
2 作爲頭等對象,函數還可以被傳遞給其他函數或作爲其他函數的返回值。
3 頭等函數的特性可以用來抽象並傳遞程序中的行爲。
4 函數可以嵌套,並且可以捕獲並攜帶父函數的一些狀態。具有這種行爲的函數稱爲閉包
。
5 對象可以被設置爲可調用的,因此很多情況下可以將其作爲函數對待。
1.1 函數是對象
def yell(text):
return text.upper() + '...'
bark = yell
print(bark) # <function yell at 0x0000027E7DDAD1E0>
print(yell) # <function yell at 0x0000027E7DDAD1E0>
demo1_1 = bark("Hello world | function test demo 1")
print(demo1_1) # HELLO WORLD | FUNCTION TEST DEMO 1...
del yell
# yell("Hello") # NameError: name 'yell' is not defined
hi = bark("Hello")
print(hi) # HELLO...
print(bark.__name__) # yell
1.2 函數可傳遞給其他函數
def greet(func):
greeting = func('Hi, I am a Python program')
print(greeting)
print(greet(bark)) # HI, I AM A PYTHON PROGRAM...
Python 中具有代表性的高階函數是內置的 map
函數。map
接受一個函數對象和一個可迭代對象,然後在可迭代對象中的每個元素上調用該函數來生成結果。
下面通過將 bark
函數映射到多個問候語中來格式化字符串:
print(list(map(bark, ['hello', 'hey', 'hi']))) # ['HELLO...', 'HEY...', 'HI...']
1.3 嵌套函數
def speak(text):
def whisper(t):
return t.upper() + '!!!'
return whisper(text)
print(speak('Hello, World')) # HELLO, WORLD!!!
1.4 閉包示例
def get_speak_func(text, volume):
# 內部函數 whisper 和 _yell,注意其中並沒有 text 參數
def whisper():
return text.lower() + '...'
def _yell():
return text.upper() + '!'
if volume > 0.5:
return _yell
else:
return whisper
hello = get_speak_func('Hello, World', 0.7)()
print(hello) # Output: 'HELLO, WORLD!'
2 lambda 是單表達式函數
簡單示例
>>> add = lambda x, y: x + y
>>> add(5, 3)
8
2.1 函數表達式
expert = (lambda x, y: x + y)(5, 3)
print(expert) # 8
2.2 lambda 使用場景:排序
tuples = [(1, 'd'), (2, 'b'), (4, 'a'), (3, 'c')]
tuples = sorted(tuples, key=lambda x: x[1], reverse=False)
print(tuples) # [(4, 'a'), (2, 'b'), (3, 'c'), (1, 'd')]
將 lambda 和 map()
或 filter()
結合起來構建複雜的表達式也很難讓人理解,
此時用列表解析式或生成器表達式通常會清晰不少:
# 有害:
>>> list(filter(lambda x: x % 2 == 0, range(16)))
[0, 2, 4, 6, 8, 10, 12, 14]
# 清晰:
>>> [x for x in range(16) if x % 2 == 0]
[0, 2, 4, 6, 8, 10, 12, 14]
3 裝飾器的力量
裝飾器的一大用途是將通用的功能應用到現有的類或函數的行爲上,這些功能包括:
1 日誌(logging
)
2 訪問控制和授權
3 衡量函數,如執行時間
4 限制請求速率(rate-limiting
)
5 緩存,等等
def trace(func):
def wrapper(*args, **kwargs):
print(f'TRACE: calling {func.__name__}() '
f'with {args}, {kwargs}')
original_result = func(*args, **kwargs)
print(f'TRACE: {func.__name__}() '
f'returned {original_result!r}')
return original_result
return wrapper
@trace
def say(name, line):
return f'{name}: {line}'
text = say('Jane', 'Hello, World')
print(text)
# TRACE: calling say() with ('Jane', 'Hello, World'), {}
# TRACE: say() returned 'Jane: Hello, World'
# Jane: Hello, World
Python 裝飾器寫日誌
示例如下
from functools import wraps
def log(func):
@wraps(func)
def wrapper(*args, **kw):
if func.__name__ == "debug":
msg = "debug {}".format(args[0])
elif func.__name__ == "info":
msg = "info {}".format(args[0])
else:
msg = "unknown {}".format(args[0])
return func(msg, **kw)
return wrapper
@log
def debug(msg):
print(msg)
@log
def info(msg):
print(msg)
if __name__ == "__main__":
debug("bug!")
info("msg.")
# 輸出結果如下:
# debug bug!
# info msg.
4 有趣的 *args
和 **kwargs
*args
和 **kwargs
用於在 Python 中編寫變長參數的函數。
*args
收集額外的位置參數組成元組。**kwargs
收集額外的關鍵字參數組成字典。
def foo(required, *args, **kwargs):
print(required)
if args:
print(args)
if kwargs:
print(kwargs)
# print(foo()) # TypeError: foo() missing 1 required positional argument: 'required'
foo('hello') # hello
foo('hello', 1, 2, 3)
# hello
# (1, 2, 3)
foo('hello', 1, 2, 3, key1='value', key2=999)
# hello
# (1, 2, 3)
# {'key1': 'value', 'key2': 999}
5 函數參數解包
*
和 **
操作符有一個非常棒但有點神祕的功能,那就是用來從序列和字典中 “解包” 函數參數。
高效使用參數解包有助於爲模塊和函數編寫更靈活的接口。
def print_vector(x, y, z):
print('<%s, %s, %s>' % (x, y, z))
express = (x * x for x in range(3))
print_vector(*express) # <0, 1, 4>
dict_vec = {'y': 0, 'z': 1, 'x': 1}
print_vector(**dict_vec) # <1, 0, 1>
print_vector(*dict_vec) # <y, z, x>
6 返回空值
Python 在所有函數的末尾添加了隱式的 return None
語句。因此,如果函數沒有指定返回值,默認情況下會返回 None。
返回空值是 Python 的核心功能,但是使用顯式
的 return None
語句能更清楚地表達代碼的意圖。
def foo1(value):
"""建議顯示說明返回值 None,方便以後維護"""
if value:
return value
else:
return None
def foo2(value):
"""純return 語句,相當於`return None`"""
if value:
return value
else:
return
def foo3(value):
"""無return 語句,也相當於`return None`"""
if value:
return value