"functools" --- 可呼叫物件上的高階函式與操作
********************************************

**原始碼：**Lib/functools.py

======================================================================

"functools" 模組用於高階函式：作用於或回傳其他函式的函式。一般來說，任
何可呼叫物件都可以被視為用於此模組的函式。

"functools" 模組定義了以下函式：

@functools.cache(user_function)

   簡單的輕量級無繫結函式快取 (Simple lightweight unbounded function
   cache)。有時稱之為 "memoize"（記憶化）。

   和 "lru_cache(maxsize=None)" 回傳相同的值，為函式引數建立一個字典查
   找的薄包裝器。因為它永遠不需要丟棄舊值，所以這比有大小限制的
   "lru_cache()" 更小、更快。

   舉例來說：

      @cache
      def factorial(n):
          return n * factorial(n-1) if n else 1

      >>> factorial(10)   # no previously cached result, makes 11 recursive calls
      3628800
      >>> factorial(5)    # no new calls, just returns the cached result
      120
      >>> factorial(12)   # two new recursive calls, factorial(10) is cached
      479001600

   該快取是執行緒安全的 (threadsafe)，因此包裝的函式可以在多個執行緒中
   使用。這意味著底層資料結構在並行更新期間將保持連貫 (coherent)。

   如果另一個執行緒在初始呼叫完成並快取之前進行額外的呼叫，則包裝的函
   式可能會被多次呼叫。

   在 3.9 版被加入.

@functools.cached_property(func)

   將類別的一個方法轉換為屬性 (property)，其值會計算一次，然後在實例的
   生命週期內快取為普通屬性。類似 "property()"，但增加了快取機制。對於
   除使用該裝飾器的屬性外實質上幾乎是不可變 (immutable) 的實例，針對其
   所需要繁重計算會很有用。

   範例：

      class DataSet:

          def __init__(self, sequence_of_numbers):
              self._data = tuple(sequence_of_numbers)

          @cached_property
          def stdev(self):
              return statistics.stdev(self._data)

   "cached_property()" 的機制與 "property()" 有所不同。除非定義了
   setter，否則常規屬性會阻止屬性的寫入。相反地，*cached_property* 則
   允許寫入。

   *cached_property* 裝飾器僅在查找時且僅在同名屬性不存在時運行。當它
   運行時，*cached_property* 會寫入同名的屬性。後續屬性讀取和寫入優先
   於 *cached_property* 方法，並且它的工作方式與普通屬性類似。

   可以透過刪除屬性來清除快取的值，這使得 *cached_property* 方法可以再
   次運行。

   *cached_property* 無法防止多執行緒使用中可能出現的競爭條件 (race
   condition)。getter 函式可以在同一個實例上運行多次，最後一次運行會設
   定快取的值。所以快取的屬性最好是冪等的 (idempotent)，或者在一個實例
   上運行多次不會有害，就不會有問題。如果同步是必要的，請在裝飾的
   getter 函式內部或在快取的屬性存取周圍實作必要的鎖。

   請注意，此裝飾器會干擾 **PEP 412** 金鑰共用字典的操作。這意味著實例
   字典可能比平常佔用更多的空間。

   此外，此裝飾器要求每個實例上的 "__dict__" 屬性是可變對映 (mutable
   mapping)。這意味著它不適用於某些型別，例如元類別 (metaclass)（因為
   型別實例上的 "__dict__" 屬性是類別命名空間的唯讀代理），以及那些指
   定 "__slots__" 而不包含 "__dict__" 的型別作為有定義的插槽之一（因為
   此種類別根本不提供 "__dict__" 屬性）。

   如果可變對映不可用或需要金鑰共享以節省空間，則也可以透過在
   "lru_cache()" 之上堆疊 "property()" 來實作類似於
   "cached_property()" 的效果。請參閱如何快取方法呼叫？以了解有關這與
   "cached_property()" 間不同之處的更多詳細資訊。

   在 3.8 版被加入.

   在 3.12 版的變更: 在 Python 3.12 之前，"cached_property" 包含一個未
   以文件記錄的鎖，以確保在多執行緒使用中能保證 getter 函式對於每個實
   例只會執行一次。然而，鎖是針對每個屬性，而不是針對每個實例，這可能
   會導致無法被接受的嚴重鎖爭用 (lock contention)。在 Python 3.12+ 中
   ，此鎖已被刪除。

functools.cmp_to_key(func)

   將舊式比較函式轉換為*鍵函式*，能與接受鍵函式的工具一起使用（例如
   "sorted()"、"min()"、"max()"、"heapq.nlargest()"、
   "heapq.nsmallest()"、"itertools.groupby()"）。此函式主要作為轉換工
   具，用於從有支援使用比較函式的 Python 2 轉換成的程式。

   比較函式是任何能接受兩個引數、對它們進行比較，並回傳負數（小於）、
   零（相等）或正數（大於）的可呼叫物件。鍵函式是接受一個引數並回傳另
   一個用作排序鍵之值的可呼叫物件。

   範例：

      sorted(iterable, key=cmp_to_key(locale.strcoll))  # locale-aware sort order

   有關排序範例和簡短的排序教學，請參閱排序技法。

   在 3.2 版被加入.

@functools.lru_cache(user_function)
@functools.lru_cache(maxsize=128, typed=False)

   以記憶化可呼叫物件來包裝函式的裝飾器，最多可省去 *maxsize* 個最近的
   呼叫。當使用相同引數定期呼叫繁重的或 I/O 密集的函式時，它可以節省時
   間。

   該快取是執行緒安全的 (threadsafe)，因此包裝的函式可以在多個執行緒中
   使用。這意味著底層資料結構在並行更新期間將保持連貫 (coherent)。

   如果另一個執行緒在初始呼叫完成並快取之前進行額外的呼叫，則包裝的函
   式可能會被多次呼叫。

   由於字典用於快取結果，因此函式的位置引數和關鍵字引數必須是*可雜湊的
   *。

   不同的引數模式可以被認為是具有不同快取條目的不同呼叫。例如，"f(a=1,
   b=2)" 和 "f(b=2, a=1)" 的關鍵字引數順序不同，並且可能有兩個不同的快
   取條目。

   如果指定了 *user_function*，則它必須是個可呼叫物件。這使得
   *lru_cache* 裝飾器能夠直接應用於使用者函式，將 *maxsize* 保留為其預
   設值 128：

      @lru_cache
      def count_vowels(sentence):
          return sum(sentence.count(vowel) for vowel in 'AEIOUaeiou')

   如果 *maxsize* 設定為 "None"，則 LRU 功能將被停用，且快取可以無限制
   地成長。

   如果 *typed* 設定為 true，不同型別的函式引數將會被單獨快取起來。如
   果 *typed* 為 false，則實作通常會將它們視為等效呼叫，並且僅快取單一
   結果。（某些型別，例如 *str* 和 *int* 可能會被單獨快取起來，即使
   *typed* 為 false。）

   請注意，型別特異性 (type specificity) 僅適用於函式的直接引數而不是
   其內容。純量 (scalar) 引數 "Decimal(42)" 和 "Fraction(42)" 被視為具
   有不同結果的不同呼叫。相反地，元組引數 "('answer', Decimal(42))" 和
   "('answer', Fraction(42))" 被視為等效。

   包裝的函式使用一個 "cache_parameters()" 函式來進行偵測，該函式回傳
   一個新的 "dict" 以顯示 *maxsize* 和 *typed* 的值。這僅能顯示資訊，
   改變其值不會有任何效果。

   為了輔助測量快取的有效性並調整 *maxsize* 參數，包裝的函式使用了一個
   "cache_info()" 函式來做檢測，該函式會回傳一個*附名元組*來顯示
   *hits*、*misses*、*maxsize* 和 *currsize*。

   裝飾器還提供了一個 "cache_clear()" 函式來清除或使快取失效。

   原本的底層函式可以透過 "__wrapped__" 屬性存取。這對於要自我檢查
   (introspection)、繞過快取或使用不同的快取重新包裝函式時非常有用。

   快取會保留對引數和回傳值的參照，直到快取過時 (age out) 或快取被清除
   為止。

   如果方法被快取起來，則 "self" 實例引數將包含在快取中。請參閱如何快
   取方法呼叫？

   當最近的呼叫是即將發生之呼叫的最佳預測因子時（例如新聞伺服器上最受
   歡迎的文章往往每天都會發生變化），LRU (least recently used) 快取能
   發揮最好的效果。快取的大小限制可確保快取不會在長時間運行的行程（例
   如 Web 伺服器）上無限制地成長。

   一般來說，僅當你想要重複使用先前計算的值時才應使用 LRU 快取。因此，
   快取具有 side-effects 的函式、需要在每次呼叫時建立不同可變物件的函
   式（例如產生器和非同步函式）或不純函式（impure function，例如
   time() 或 random()）是沒有意義的。

   靜態網頁內容的 LRU 快取範例：

      @lru_cache(maxsize=32)
      def get_pep(num):
          '取得 Python 改進提案的文字'
          resource = f'https://peps.python.org/pep-{num:04d}'
          try:
              with urllib.request.urlopen(resource) as s:
                  return s.read()
          except urllib.error.HTTPError:
              return 'Not Found'

      >>> for n in 8, 290, 308, 320, 8, 218, 320, 279, 289, 320, 9991:
      ...     pep = get_pep(n)
      ...     print(n, len(pep))

      >>> get_pep.cache_info()
      CacheInfo(hits=3, misses=8, maxsize=32, currsize=8)

   使用快取來實作動態規劃 (dynamic programming) 技法以有效率地計算費波
   那契數 (Fibonacci numbers) 的範例：

      @lru_cache(maxsize=None)
      def fib(n):
          if n < 2:
              return n
          return fib(n-1) + fib(n-2)

      >>> [fib(n) for n in range(16)]
      [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]

      >>> fib.cache_info()
      CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)

   在 3.2 版被加入.

   在 3.3 版的變更: 新增 *typed* 選項。

   在 3.8 版的變更: 新增 *user_function* 選項。

   在 3.9 版的變更: 新增 "cache_parameters()" 函式。

@functools.total_ordering

   給定一個定義一個或多個 rich comparison 排序方法的類別，該類別裝飾器
   會提供其餘部分。這簡化了指定所有可能的 rich comparison 操作所涉及的
   工作：

   類別必須定義 "__lt__()"、"__le__()"、"__gt__()" 或 "__ge__()" 其中
   之一。此外，該類別應該提供 "__eq__()" 方法。

   舉例來說：

      @total_ordering
      class Student:
          def _is_valid_operand(self, other):
              return (hasattr(other, "lastname") and
                      hasattr(other, "firstname"))
          def __eq__(self, other):
              if not self._is_valid_operand(other):
                  return NotImplemented
              return ((self.lastname.lower(), self.firstname.lower()) ==
                      (other.lastname.lower(), other.firstname.lower()))
          def __lt__(self, other):
              if not self._is_valid_operand(other):
                  return NotImplemented
              return ((self.lastname.lower(), self.firstname.lower()) <
                      (other.lastname.lower(), other.firstname.lower()))

   備註:

     雖然此裝飾器可以輕鬆建立能好好運作的完全有序型別 (totally ordered
     types)，但它*的確*以衍生比較方法的執行速度較慢和堆疊追蹤 (stack
     trace) 較複雜做為其代價。如果效能基準測試顯示這是給定應用程式的效
     能瓶頸，那麼實作全部六種 rich comparison 方法通常能輕鬆地提升速度
     。

   備註:

     此裝飾器不會嘗試覆寫類別*或其超類別 (superclass)*中宣告的方法。這
     意味著如果超類別定義了比較運算子，*total_ordering* 將不會再次實作
     它，即使原始方法是抽象的。

   在 3.2 版被加入.

   在 3.4 版的變更: 現在支援從底層對於未識別型別的比較函式回傳
   "NotImplemented"。

functools.partial(func, /, *args, **keywords)

   回傳一個新的 partial 物件，它在被呼叫時的行為類似於使用位置引數
   *args* 和關鍵字引數 *keywords* 呼叫的 *func*。如果向呼叫提供更多引
   數，它們將被附加到 *args*。如果提供了額外的關鍵字引數，它們會擴充並
   覆寫 *keywords*。大致相當於：

      def partial(func, /, *args, **keywords):
          def newfunc(*fargs, **fkeywords):
              newkeywords = {**keywords, **fkeywords}
              return func(*args, *fargs, **newkeywords)
          newfunc.func = func
          newfunc.args = args
          newfunc.keywords = keywords
          return newfunc

   "partial()" 用於部分函式應用程序，它「凍結」函式引數和/或關鍵字的某
   些部分，從而產生具有簡化簽名的新物件。例如，"partial()" 可用來建立
   可呼叫函式，其行為類似於 "int()" 函式，其中 *base* 引數預設為 2：

   >>> from functools import partial
   >>> basetwo = partial(int, base=2)
   >>> basetwo.__doc__ = 'Convert base 2 string to an int.'
   >>> basetwo('10010')
   18

class functools.partialmethod(func, /, *args, **keywords)

   回傳一個新的 "partialmethod" 描述器 (descriptor)，其行為類似於
   "partial"，只不過它被設計為用於方法定義而不能直接呼叫。

   *func* 必須是一個 *descriptor* 或可呼叫物件（兩者兼具的物件，就像普
   通函式一樣，會被當作描述器處理）。

   當 *func* 是描述器時（例如普通的 Python 函式、"classmethod()"、
   "staticmethod()"、"abstractmethod()" 或 "partialmethod" 的另一個實
   例），對 "__get__" 的呼叫將被委託 (delegated) 給底層描述器，且一個
   適當的 partial 物件會被作為結果回傳。

   當 *func* 是非描述器可呼叫物件 (non-descriptor callable) 時，會動態
   建立適當的繫結方法 (bound method)。當被作為方法使用時，其行為類似於
   普通的 Python 函式：*self* 引數將作為第一個位置引數插入，甚至會在提
   供給 "partialmethod" 建構函式的 *args* 和 *keywords* 的前面。

   範例：

      >>> class Cell:
      ...     def __init__(self):
      ...         self._alive = False
      ...     @property
      ...     def alive(self):
      ...         return self._alive
      ...     def set_state(self, state):
      ...         self._alive = bool(state)
      ...     set_alive = partialmethod(set_state, True)
      ...     set_dead = partialmethod(set_state, False)
      ...
      >>> c = Cell()
      >>> c.alive
      False
      >>> c.set_alive()
      >>> c.alive
      True

   在 3.4 版被加入.

functools.reduce(function, iterable, [initial, ]/)

   從左到右，將兩個引數的 *function* 累加運用到 *iterable* 的項目上，
   從而將可疊代物件減少為單一值。例如，"reduce(lambda x, y: x+y, [1,
   2, 3, 4, 5])" 會計算出 "((((1+2)+3)+4)+5)"。左邊的引數 *x* 是累積值
   ，右邊的引數 *y* 是來自 *iterable* 的更新值。如果可選的 *initial*
   存在，則在計算中會將其放置在可疊代物件的項目之前，並在可疊代物件為
   空時作為預設值。如果未給定 *initial* 且 *iterable* 僅包含一個項目，
   則回傳第一個項目。

   大致相當於：

      initial_missing = object()

      def reduce(function, iterable, initial=initial_missing, /):
          it = iter(iterable)
          if initial is initial_missing:
              value = next(it)
          else:
              value = initial
          for element in it:
              value = function(value, element)
          return value

   請參閱 "itertools.accumulate()" 以了解產生 (yield) 所有中間值
   (intermediate value) 的疊代器。

@functools.singledispatch

   將函式轉換為*單一調度**泛型函式*。

   若要定義泛型函式，請使用 "@singledispatch" 裝飾器對其裝飾。請注意，
   使用 "@singledispatch" 定義函式時，分派調度 (dispatch) 是發生在第一
   個引數的型別上：

      >>> from functools import singledispatch
      >>> @singledispatch
      ... def fun(arg, verbose=False):
      ...     if verbose:
      ...         print("Let me just say,", end=" ")
      ...     print(arg)

   若要為函式新增過載實作，請使用泛型函式的 "register()" 屬性，該屬性
   可用作裝飾器。對於以型別來註釋的函式，裝飾器將自動推斷第一個引數的
   型別：

      >>> @fun.register
      ... def _(arg: int, verbose=False):
      ...     if verbose:
      ...         print("Strength in numbers, eh?", end=" ")
      ...     print(arg)
      ...
      >>> @fun.register
      ... def _(arg: list, verbose=False):
      ...     if verbose:
      ...         print("Enumerate this:")
      ...     for i, elem in enumerate(arg):
      ...         print(i, elem)

   也可以使用 "types.UnionType" 和 "typing.Union"：

      >>> @fun.register
      ... def _(arg: int | float, verbose=False):
      ...     if verbose:
      ...         print("Strength in numbers, eh?", end=" ")
      ...     print(arg)
      ...
      >>> from typing import Union
      >>> @fun.register
      ... def _(arg: Union[list, set], verbose=False):
      ...     if verbose:
      ...         print("Enumerate this:")
      ...     for i, elem in enumerate(arg):
      ...         print(i, elem)
      ...

   對於不使用型別註釋的程式碼，可以將適當的型別引數明確傳遞給裝飾器本
   身：

      >>> @fun.register(complex)
      ... def _(arg, verbose=False):
      ...     if verbose:
      ...         print("Better than complicated.", end=" ")
      ...     print(arg.real, arg.imag)
      ...

   For code that dispatches on a collections type (e.g., "list"), but
   wants to typehint the items of the collection (e.g., "list[int]"),
   the dispatch type should be passed explicitly to the decorator
   itself with the typehint going into the function definition:

      >>> @fun.register(list)
      ... def _(arg: list[int], verbose=False):
      ...     if verbose:
      ...         print("Enumerate this:")
      ...     for i, elem in enumerate(arg):
      ...         print(i, elem)

   備註:

     At runtime the function will dispatch on an instance of a list
     regardless of the type contained within the list i.e. "[1,2,3]"
     will be dispatched the same as "["foo", "bar", "baz"]". The
     annotation provided in this example is for static type checkers
     only and has no runtime impact.

   若要啟用註冊 *lambdas* 和預先存在的函式，"register()" 屬性也能以函
   式形式使用：

      >>> def nothing(arg, verbose=False):
      ...     print("Nothing.")
      ...
      >>> fun.register(type(None), nothing)

   "register()" 屬性回傳未加裝飾器的函式。這讓使得裝飾器堆疊
   (decorator stacking)、"pickling" 以及為每個變體獨立建立單元測試成為
   可能：

      >>> @fun.register(float)
      ... @fun.register(Decimal)
      ... def fun_num(arg, verbose=False):
      ...     if verbose:
      ...         print("Half of your number:", end=" ")
      ...     print(arg / 2)
      ...
      >>> fun_num is fun
      False

   呼叫時，泛型函式會分派第一個引數的型別：

      >>> fun("Hello, world.")
      Hello, world.
      >>> fun("test.", verbose=True)
      Let me just say, test.
      >>> fun(42, verbose=True)
      Strength in numbers, eh? 42
      >>> fun(['spam', 'spam', 'eggs', 'spam'], verbose=True)
      Enumerate this:
      0 spam
      1 spam
      2 eggs
      3 spam
      >>> fun(None)
      Nothing.
      >>> fun(1.23)
      0.615

   如果沒有為特定型別註冊實作，則使用其方法解析順序 (method resolution
   order) 來尋找更通用的實作。用 "@singledispatch" 裝飾的原始函式是為
   基底 "object" 型別註冊的，這意味著如果沒有找到更好的實作就會使用它
   。

   如果一個實作有被註冊到一個*抽象基底類別*，則基底類別的虛擬子類別將
   被分派到該實作：

      >>> from collections.abc import Mapping
      >>> @fun.register
      ... def _(arg: Mapping, verbose=False):
      ...     if verbose:
      ...         print("Keys & Values")
      ...     for key, value in arg.items():
      ...         print(key, "=>", value)
      ...
      >>> fun({"a": "b"})
      a => b

   若要檢查泛型函式將為給定型別選擇哪種實作，請使用 "dispatch()" 屬性
   ：

      >>> fun.dispatch(float)
      <function fun_num at 0x1035a2840>
      >>> fun.dispatch(dict)    # note: default implementation
      <function fun at 0x103fe0000>

   若要存取所有已註冊的實作，請使用唯讀 "registry" 屬性：

      >>> fun.registry.keys()
      dict_keys([<class 'NoneType'>, <class 'int'>, <class 'object'>,
                <class 'decimal.Decimal'>, <class 'list'>,
                <class 'float'>])
      >>> fun.registry[float]
      <function fun_num at 0x1035a2840>
      >>> fun.registry[object]
      <function fun at 0x103fe0000>

   在 3.4 版被加入.

   在 3.7 版的變更: "register()" 屬性現在支援使用型別註釋。

   在 3.11 版的變更: "register()" 屬性現在支援以 "types.UnionType" 和
   "typing.Union" 作為型別註釋。

class functools.singledispatchmethod(func)

   將方法轉換為*單一調度**泛型函式*。

   To define a generic method, decorate it with the
   "@singledispatchmethod" decorator. When defining a method using
   "@singledispatchmethod", note that the dispatch happens on the type
   of the first non-*self* or non-*cls* argument:

      class Negator:
          @singledispatchmethod
          def neg(self, arg):
              raise NotImplementedError("Cannot negate a")

          @neg.register
          def _(self, arg: int):
              return -arg

          @neg.register
          def _(self, arg: bool):
              return not arg

   "@singledispatchmethod" supports nesting with other decorators such
   as "@classmethod". Note that to allow for "dispatcher.register",
   "singledispatchmethod" must be the *outer most* decorator. Here is
   the "Negator" class with the "neg" methods bound to the class,
   rather than an instance of the class:

      class Negator:
          @singledispatchmethod
          @classmethod
          def neg(cls, arg):
              raise NotImplementedError("Cannot negate a")

          @neg.register
          @classmethod
          def _(cls, arg: int):
              return -arg

          @neg.register
          @classmethod
          def _(cls, arg: bool):
              return not arg

   The same pattern can be used for other similar decorators:
   "@staticmethod", "@~abc.abstractmethod", and others.

   在 3.8 版被加入.

functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)

   更新 *wrapper* 函式，使其看起來像 *wrapped* 函式。可選引數是元組，
   用於指定原始函式的哪些屬性直接賦值給包裝函式上的匹配屬性，以及包裝
   函式的哪些屬性使用原始函式中的對應屬性進行更新。這些引數的預設值是
   模組層級的常數 "WRAPPER_ASSIGNMENTS"（它賦值給包裝函式的
   "__module__"、"__name__"、"__qualname__"、"__annotations__"、
   "__type_params__" 和 "__doc__" 文件字串 (docstring））和
   "WRAPPER_UPDATES"（更新包裝器函式的 "__dict__"，即實例字典）。

   為了允許出於內省 (introspection) 和其他目的所對原始函式的存取（例如
   繞過快取裝飾器，如 "lru_cache()"），此函式會自動向包裝器新增
   "__wrapped__" 屬性，該包裝器參照被包裝的函式。

   此函式的主要用途是在 *decorator* 函式中，它包裝函式並回傳包裝器。如
   果包裝器函式未更新，則回傳函式的元資料 (metadata) 將反映包裝器定義
   而非原始函式定義，這通常不太會有幫助。

   "update_wrapper()" 可以與函式以外的可呼叫物件一起使用。被包裝的物件
   中缺少的 *assigned* 或 *updated* 中指定的任何屬性都將被忽略（即此函
   式不會嘗試在包裝器函式上設定它們）。如果包裝函式本身缺少 *updated*
   中指定的任何屬性，仍然會引發 "AttributeError"。

   在 3.2 版的變更: 現在會自動新增 "__wrapped__" 屬性。現在預設會複製
   "__annotations__" 屬性。缺少的屬性不再觸發 "AttributeError"。

   在 3.4 版的變更: "__wrapped__" 屬性現在都會參照包裝函式，即便函式有
   定義 "__wrapped__" 屬性。（參見 bpo-17482）

   在 3.12 版的變更: 現在預設會複製 "__type_params__" 屬性。

@functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)

   這是一個方便的函式，用於在定義包裝器函式時呼叫 "update_wrapper()"
   作為函式裝飾器。它相當於 "partial(update_wrapper, wrapped=wrapped,
   assigned=assigned, updated=updated)"。例如：

      >>> from functools import wraps
      >>> def my_decorator(f):
      ...     @wraps(f)
      ...     def wrapper(*args, **kwds):
      ...         print('Calling decorated function')
      ...         return f(*args, **kwds)
      ...     return wrapper
      ...
      >>> @my_decorator
      ... def example():
      ...     """Docstring"""
      ...     print('Called example function')
      ...
      >>> example()
      Calling decorated function
      Called example function
      >>> example.__name__
      'example'
      >>> example.__doc__
      'Docstring'

   如果不使用這個裝飾器工廠 (decorator factory)，範例函式的名稱將會是
   "'wrapper'"，並且原始 "example()" 的文件字串將會遺失。


"partial" 物件
==============

"partial" 物件是由 "partial()" 所建立的可呼叫物件。它們有三個唯讀屬性
：

partial.func

   一個可呼叫的物件或函式。對 "partial" 物件的呼叫將被轉送到帶有新引數
   和關鍵字的 "func"。

partial.args

   最左邊的位置引數將會被加入到提供給 "partial" 物件呼叫的位置引數的前
   面。

partial.keywords

   呼叫 "partial" 物件時將提供的關鍵字引數。

"partial" 物件與函式物件類似，因為它們是可呼叫的、可弱參照的 (weak
referencable) 且可以具有屬性。有一些重要的區別，例如，"__name__" 和
"function.__doc__" 屬性不會自動建立。此外，類別中定義的 "partial" 物件
的行為類似於靜態方法，並且在實例屬性查找期間不會轉換為繫結方法。
