Skip to content

python

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 讀書筆記(二)

Generator as Coroutines

  • Python

Generator as Coroutines

  • cooperative multitasking (cooperative routines)
  • concurrent not parallel (python program execute on a single thread)

The way to create coroutines:

  • generators (asyncio)
  • native coroutines (using async /await)

Concepts

  • concurrency: tasks start, run and complete in overlapping time periods
  • parallelism: tasks run simultaneousely

image

  • cooperative: control relinquished to other task voluntarily, control by application(developer)
  • preemptive: control relinquished to other task involuntarily, control by the OS.

    some sort of scheduler involved

image

  • Global Interpreter Lock(GIL)

    Only one native thread excutes at a time.

    Use Process based parallelism to avoid GIL. Not Thread based.

    The Python threading module uses threads instead of processes. Threads uniquely run in the same unique memory heap. Whereas Processes run in separate memory heaps. This makes sharing information harder with processes and object instances. One problem arises because threads use the same memory heap, multiple threads can write to the same location in the memory heap which is why the global interpreter lock(GIL) in CPython was created as a mutex to prevent it from happening.

Make the right choice

  • CPU Bound => Multi processing
  • I/O Bound, Fast I/O, Limit Connections => Muilti Threading
  • I/O Bound, Slow I/O, Many Connections => Concurrency

Use deque

Much more efficient way to implement the stack and queue.

Operate 10,000 items take 1,000 times average:

(times in seconds) list deque
append(right) 0.87 0.87
pop(right) 0.002 0.0005
insert(left) 20.8 0.84
pop(left) 0.012 0.0005

Use unlimited deque with deque() or deque(iterable)
Use limited deque with deque(maxlen=n). If full, a corresponding number of items are discarded from the opposite end.

Implement producer / consumer coroutine using deque

Implement simple event loop

Read More »Generator as Coroutines

Context Manager

  • Python

Context Manager

what is context

the state surrounding a section of code

why we need a context manager

  • writing try/finally every time can get cumbersom
  • easy to forget closing the file

use cases

Useful for program that needs Enter / Exit handeling

  • create / releasing resources
  • database transaction
  • set and reset decimal context

Common patterns

  • open / close
  • lock / release
  • change / reset
  • start / stop
  • enter / exit

protocal

implement these two dunder methods:

  • __enter__

    perform the setup, optionally return an object

  • __exit__

    receives error (silence or propagate)

    • need arguments exc_type, exc_value, exc_trace to handle exception
    • return True to silence exception

    perform clean up

examples

contextlib

nested contexts

Generator

  • Python

Generator

  • A type of iterator
  • generator function: function that uses yield statement
  • implement the iterator protocal, call next
  • raise StopIteration exhausted

Less code

Implement an iterator

Implement a generator

More efficient

Generator Comprehensions

  • local scope
  • lazy evaluation
  • is an iterator, can be exhausted

Delegating Generator

Use the syntax yield from to yield items in a generator

Iterable and Iterator

  • Python

Iterator & Iterable

iterator

  • get next item (__next__)
  • no indexes needed (Don’t need to be Sequence type)
  • consumable

iterable

  • collections that implement iterator

Protocal

Python need to count on certain funcionality: __next____iter__StopIteration

compare to sequence type

iteration can be more general than sequential indexing, we only need:

  • a bucket of items: collection, container
  • a way to get the next item, no need to care about ordering
  • an exception to raise if there is no next item

try to custom an iterator ourselfs:

Why re-create?

Seperate the Collection from the iterator

Iterable object

  • Maintaining the data of the collection is one object
  • Created once
  • implements __iter__, return a new iterator instance

Iterator object

  • Iterating over that data should be another object
  • throw away the iterator but don’t throw away the collection
  • Created every time
  • implements __iter__, return itself
  • implements __next__, return next item

iterable can be lazy

Caculate the next itme in an iterable until it’s actually requested

lazy evaluation

  • often used in class properties
  • properties of classes may not always populated when the object is created
  • value of property only becomes known when the property is requested/deferred

infnite iterables

  • itertools.cycle

Python Built-ins

  • range: return iterable
  • zip: return iterator
  • enumerate: return iterator
  • open: return iterator
  • reversed: return iterator

The type is important. Iterator object can be only iter over once.

iter()

when iter is called:

  • Python first looks for __iter__, if not then:
  • look for __getitem__ and create an iterator, if not then:
  • raise TypeError

Test it:

The __iter__ must return an iterator!

Iterating callable

iterator delegation

Example 1

Example 2

序列 – Python Sequence

  • Python

Sequence

必須足以下條件:

  • 物件的集合
  • countable
  • zero based indexing (__getitem__)
  • 為什麼 index 要從0開始?
    • 0 based: 0 <= n < len(s)
    • 1 based: 1 <= n < len(s) + 1 Upper bound 用小於的原因是計算長度時不須再+1
  • 有序(positional ordering)
    • 舉例來說 list 和 set 都是物件的容器,但 list 可以被排序, set 不行,因此 list 是 Sequence Type 而 set 不是

特性:

  • Homogeneous vs Heterogeneous 同質即序列的物件型態必須是相同的
  • Iterable vs non iterable 可以迭代的容器不一定是序列,如set
  • Mutable vs Immutable Mutable sequence can be modified. 要注意的是在操作新序列的時候更動到原本的序列(in-place),如 reverse()

以 list 為例,這幾個操作皆為原地算法(inplace):

  • l.clear()
  • l.append()
  • l.pop()
  • l.extend()
  • l.insert()
  • l +=
  • l *=
  • l[somesliceobj] = 若是 concat(+)、repetition(*)、slicing 都是關聯至新的物件參考

要注意的是,容器序列(儲存物件參考)的 concat 和 repetition 有可能只是儲存多個相同物件的參考

Read More »序列 – Python Sequence