Skip to content

decorator

Fluent Python 讀書筆記(二)

一級函式

  • 在 Python 所有函式都是一級物件:
    • 可在執行階段建立
    • 可以指派給變數,或資料結構內的元素
    • 可以當成引數傳給函式
    • 可以當成函式的結果回傳
  • 如果一個函式的引數是包含函式,或回傳的物件是函式,它就是高階函式 (higher-order function),經典的例子是 mapfilterreduce
  • listcomp、genexp 可作 mapfilter 的工作,且更容易閱讀,後兩者已經沒有那麼重要了
  • 除了用來處理高階函式的引數外,匿名函式在 Python 並沒什麼其他用處,且通常難以閱讀
  • Python 的七種 callable
    1. User-defined functions: deflambda
    2. Built-in functions:以 C 寫成的函式,如 lentime.strftime
    3. Built-in methods:以 C 寫成的方法,如 dict.get
    4. Methods
    5. Classes: 透過 __new__ 建立,再經 __init__ 初始化
    6. Class instances:須實作 __call__(任何物件都能有函式的行為)
    7. Generator functions
  • 如同自訂類別的實例,函式會使用 __dict__ 儲存特定的使用者屬性
  • 幾個重要的函式專用特殊方法:`
    • __annotations__:參數與回傳註解
    • __closure__:綁定自由變數(free variables)的空間
    • __code__:中繼資料、及編碼後的函式內文
    • __defaults__:以 tuple 儲存正式參數的預設值
    • __kwdefaults__:以 dict 儲存限關鍵字的正式參數的預設值
  • 要知道函式需要什麼參數、以及有沒有預設值,使用 inspect 模組會比較方便。因為 __(kw)defaults__ 雖然儲存了預設值,但參數名稱卻是放在 __code__ 裡面,必須由後往前掃描一次,才能將每一個值與各自的參數連結

  • inspect.Signature 物件有一個 bind 方法可以拿來測試傳入的參數組合
  • 函式註釋(Function Annotations)常見的型態是類別,如 strint,或字串如 int > 0,註釋不會處理任何工作,會被保存在 __annotation__ 屬性裡
  • 對解譯器來說,註釋沒有意義,它只們是可能會被工具所使用的中繼資料
  • Guido 清楚地表示不想讓 Python 成為 Funtional Programming 語言(但是因為有 operatorfunctools 模組,可以善加運用在 FP 風格上)
  • 列出一些有用的 FP 工具:operator.itemgetteroperator.attrgetteroperator.methodcallerfunctools.partial
  • 在 Python 中廣泛採用 FP 語法的最大障礙,就是缺乏尾部遞迴消除 (tail-recursion elimination) 的最佳化功能
  • 「所有匿名函式都有一個嚴重的缺點:它們沒有名字」

Read More »Fluent Python 讀書筆記(二)

Python 閉包及裝飾器的應用 – Closure and Decorator in Python

  • Python

在開始前,會需要先具備Scope的基本觀念:Python變數範圍 – Scope


Closure

在函數執行時,會建立一個local scope,當函數執行完,這個local scope並不會被清除——而且只要你知道怎麼再次訪問,它都會確保你訪問得到其中的變數

Decorator

decorator的概念即是透過closure的特性,將傳入的函式經裝飾後回傳一介面,如以下範例:

經裝飾後回傳都會是同一個介面,這樣會導致debug的困難:

可以用built-in的wraps來處理,wraps是decorator,一樣要把函式傳入

decorator可以堆疊,以下這個範例其實只是做了auth(log(f))這樣的處理

Decorator Factory

至於decorator乍看之下可以傳額外的參數,其實只是再多封裝了一層decorator:

Decorator Class(用於decorator的類別)

此外,我們也能透過callable物件來製作decorator

Class Decorator (用來裝飾類別的decorator)

Python的monkey paching特性(在程式的runtime能隨意更改物件屬性),我們也可以透過decorator來裝飾類別

其他範例:
functools.totoal_ordering

Dispatching pattern

Python 變數範圍 – Variable Scope

  • Python

讓我們來討論一下這個簡單的語句:

這裡做了物件賦值(assign)這個行為,也可以說這個變數名稱(variable name)綁定(bound)到某物件上,這個物件可以透過變數(a)來訪問,但要注意…不是在程式碼任何一處都可以!

先來理解一下這些概念:

  • scope(lexical): 簡單來說,就是變數宣告(綁定)的地方

  • namespace: 命名空間紀錄這些綁定行為,每個scope都會有一份命名空間的字典來提供查找

image

Scope的類型

  • global scope
    • 或稱module scope,範圍是單個檔案(*.py)
    • 模組(或app)是層層堆疊起來的,並不會說哪裡才是真正的global環境,要說的話,最接近的可能就是built-in的變數如True、None所宣告的地方吧
  • local scope(in compile time)
    function為範圍,scope伴隨函式被呼叫時建立,變數重新綁定

當在特定的scope下找不到特定的變數,python會往外部的命名空間查找,順序是local>global>built-in。例如:

a在module scope被找到,print最後在built-in scope被找到,但找不到b,導致NameError

對於外部的scope已經存在的變數,在當前的scope再宣告一個同樣的變數名稱,這個動作叫做mask,因為在不同的scope,這樣做並不會影響到外部的變數(某個版本以前的list comprehension會發生這種狀況),除非有意為之

透過關鍵字globalnonlocal來操作

要注意nonlocal向外訪問只能訪問local scope的變數

此外,可以透過函數globalslocals輸出該scope的所有變數: