Fluent Python 讀書筆記(二)
一級函式
- 在 Python 所有函式都是一級物件:
- 可在執行階段建立
- 可以指派給變數,或資料結構內的元素
- 可以當成引數傳給函式
- 可以當成函式的結果回傳
- 如果一個函式的引數是包含函式,或回傳的物件是函式,它就是高階函式 (higher-order function),經典的例子是
map
、filter
、reduce
- listcomp、genexp 可作
map
與filter
的工作,且更容易閱讀,後兩者已經沒有那麼重要了 - 除了用來處理高階函式的引數外,匿名函式在 Python 並沒什麼其他用處,且通常難以閱讀
- Python 的七種 callable
- User-defined functions:
def
或lambda
- Built-in functions:以 C 寫成的函式,如
len
、time.strftime
- Built-in methods:以 C 寫成的方法,如
dict.get
- Methods
- Classes: 透過
__new__
建立,再經__init__
初始化 - Class instances:須實作
__call__
(任何物件都能有函式的行為) - Generator functions
- User-defined functions:
- 如同自訂類別的實例,函式會使用
__dict__
儲存特定的使用者屬性 - 幾個重要的函式專用特殊方法:`
__annotations__
:參數與回傳註解__closure__
:綁定自由變數(free variables)的空間__code__
:中繼資料、及編碼後的函式內文__defaults__
:以 tuple 儲存正式參數的預設值__kwdefaults__
:以 dict 儲存限關鍵字的正式參數的預設值
- 要知道函式需要什麼參數、以及有沒有預設值,使用
inspect
模組會比較方便。因為__(kw)defaults__
雖然儲存了預設值,但參數名稱卻是放在__code__
裡面,必須由後往前掃描一次,才能將每一個值與各自的參數連結
1 2 3 4 5 6 7 8 9 10 11 |
>>> from inspect import signature >>> def tag(name, *content, cls=None, **attrs): pass >>> sig = signature(tag) >>> for name, param in sig.parameters.items(): ... print(param.kind, ":", name, "=", param.default) ... POSITIONAL_OR_KEYWORD : name = <class 'inspect._empty'> VAR_POSITIONAL : content = <class 'inspect._empty'> KEYWORD_ONLY : cls = None VAR_KEYWORD : attrs = <class 'inspect._empty'> |
inspect.Signature
物件有一個 bind 方法可以拿來測試傳入的參數組合- 函式註釋(Function Annotations)常見的型態是類別,如
str
、int
,或字串如int > 0
,註釋不會處理任何工作,會被保存在__annotation__
屬性裡 - 對解譯器來說,註釋沒有意義,它只們是可能會被工具所使用的中繼資料
- Guido 清楚地表示不想讓 Python 成為 Funtional Programming 語言(但是因為有
operator
、functools
模組,可以善加運用在 FP 風格上) - 列出一些有用的 FP 工具:
operator.itemgetter
、operator.attrgetter
、operator.methodcaller
、functools.partial
- 在 Python 中廣泛採用 FP 語法的最大障礙,就是缺乏尾部遞迴消除 (tail-recursion elimination) 的最佳化功能
- 「所有匿名函式都有一個嚴重的缺點:它們沒有名字」