摘要:比較函數是接收兩個參數進行比較的函數,返回一個負數表示,返回表示,返回一個正數表示。表示緩存大小限制,確保不會無限制增長。大致等同于用于凍結函數的部分位置參數和或關鍵字參數而產生一個代表某部分函數功能的簡化標志。
functools模塊提供了某些高階函數(high-order function)。
functools.cmp_to_key(func)比較函數是接收兩個參數進行比較的函數,返回一個負數表示<,返回0表示=,返回一個正數表示>。key函數接收一個參數并返回另一個值作為進行排序的鍵。
將比較函數轉換為key函數,常在用到key關鍵字的函數如sotred(), min(), heapq.nlargest(), itertools,groupby()中使用。cmp_to_key主要作為過渡工具將python2中支持的比較函數進行轉換。
def numeric_compare(x, y): return x - y # python2 print(sorted([5, 2, 4, 1, 3], cmp=numeric_compare)) # python3 print(sorted([5, 2, 4, 1, 3], key=cmp_to_key(numeric_compare)))@functools.lru_cache(maxsize=128, typed=False)
使用memoize包裝函數,保存最近maxsize次的函數調用結果。在I/O-bound函數上裝飾,處理相同參數時可以節省函數執行時間。
如果maxsize為None,會禁用LRU緩存特性(并非禁用緩存)且緩存大小會無限增長。maxsize設置為2的n次方時性能最優。
如果typed為True,不同類型函數參數的執行結果會被分別緩存,例如f(3)和f(3.0)會被視為有兩個不同結果的不同調用。
因為該裝飾器使用字典緩存函數執行結果,所以函數的位置參數和關鍵字參數必須是可哈希的。
不同的參數模式可能會被視為不同的緩存實體。例如f(a=1, b=2)和f(b=2, a=1)雖然只是關鍵字順序不同但可能有兩個多帶帶的緩存實體。
被包裝的函數可以調用cache_info(),它返回一個(hits, misses, maxsize, currsize)形式的命名元組;可以調用cache_clear()清空或使緩存無效;還可以調用__wrapped__屬性繞過緩存,訪問原始的底層函數。
LRU(least recently used)緩存通常應僅用在需要重用先前計算的值的場景,其他場景如使用LRU有不良影響、每次調用需要返回不同結果、time()、random()等應禁止使用。maxsize表示緩存大小限制,確保不會無限制增長。
@lru_cache(maxsize=32) def get_pep(num): "Retrieve text of a Python Enhancement Proposal" resource = "http://www.python.org/dev/peps/pep-%04d/" % num 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)@functools.total_ordering
類裝飾器,包裝在定義了一個或多個富比較排序方法的類上,會補足其他的比較方法。
該類必須定義__lt__(), __le__(), __gt__(), 或__ge__()中至少一個方法,并建議定義__eq__()方法。
@total_ordering class Student: def __init__(self, lastname, firstname): self.lastname = lastname self.firstname = firstname 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()))
NOTE:使用這個裝飾器的代價是,裝飾器自動補足的比較方法耗費了更多的執行時間并擁有更復雜的堆棧跟蹤。如果應用性能基準測試表明是使用此裝飾器造成的瓶頸,手動實現所有六種富比較方法可以帶來直觀的速度提升。
functools.partial(func, *args, **keywords)偏函數,返回一個partial對象,調用時等同調用了使用預設位置參數和關鍵字參數的func函數。如果partial對象調用時又提供了額外的位置參數,追加到args,如果提供了額外的關鍵字參數,擴展keywords并覆蓋相同的鍵值。
大致等同于:
def partial(func, *args, **keywords): def newfunc(*fargs, **fkeywords): newkeywords = keywords.copy() newkeywords.update(fkeywords) return func(*args, *fargs, **newkeywords) newfunc.func = func newfunc.args = args newfunc.keywords = keywords return newfunc
partial()用于"凍結"函數的部分位置參數和/或關鍵字參數而產生一個代表某部分函數功能的簡化標志。
>>> from functools import partial >>> basetwo = partial(int, base=2) >>> basetwo.__doc__ = "Convert base 2 string to an int." >>> basetwo("10010") 18class functools.partialmethod(func, *args, **keywords)
后續補充
functools.reduce(function, iterable[, initializer])將可迭代對象iterable中的元素從左到右累計到接收兩個參數的函數func中。例如reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])的計算等同于((((1+2)+3)+4)+5)。
如果設置了可選參數initializer,它被放置在要計算的序列之前,并在序列為空時作為默認值;如果未提供initializer的值且序列僅包含一個元素,返回該元素。
將函數轉換為單分派泛函數(single-dispatch generic function)。
使用@singledispatch裝飾器定義一個泛函數,單分派僅限于第一個參數的類型:
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)
如果不使用類型注解,可以顯式地給裝飾器傳遞類型參數:
@fun.register(complex) def _(arg, verbose=False): if verbose: print("Better than complicated.", end=" ") print(arg.real, arg.imag)
也可以以函數的形式使用register()注冊lambda函數和已定義的函數:
def nothing(arg, verbose=False): print("Nothing.") fun.register(type(None), nothing)
register()屬性返回允許裝飾器堆疊、序列化以及創建獨立的單元測試的未裝飾的函數:
from decimal import Decimal @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
如果某個類型沒有相應的實現,將查找更通用的實現進行解析。使用@singledispatch裝飾的原始函數注冊為object類型,將在沒有更好實現的情況下使用。調用dispatch()屬性查看泛函數使用了哪個實現:
>>> fun.dispatch(float)>>> fun.dispatch(dict) # note: default implementation
調用registry屬性查看注冊的所有實現:
>>> fun.registry.keys() dict_keys([functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES), , , , , ]) >>> fun.registry[float] >>> fun.registry[object]
更新包裝函數(wrapper),使其看起來更像被包裝的原始函數(wrapped)。元組類型的可選參數assigned指定wrapped函數的哪些屬性直接分派到wrapper函數對應的屬性上,updated參數指定使用wrapped函數的哪些屬性更新wrapper函數對應的屬性。
WRAPPER_ASSIGNMENTS的默認值是"__module__", "__name__", "__qualname__", "__doc__","__annotations__"
WRAPPER_UPDATES的默認值是"__dict__"
通過訪問包裝函數的__wrapped__屬性可以獲取到被包裝的原始函數。
該函數主要用于裝飾器使用場景下,如果不更新包裝函數,返回函數的元數據將指向包裝函數而非被包裝的原始函數,一般來說沒太大意義。
def wrapper(f): def wrapper_function(*args, **kwargs): """this is a wrapper function""" return f(*args, **kwargs) # update_wrapper(wrapper_function, f) return wrapper_function @wrapper def wrapped(): """this is a wrapped function""" pass print(wrapped.__doc__) print(wrapped.__name__)
# 不使用update_wrapper的結果: >>> this is a wrapper function >>> wrapper_function # 使用update_wrapper的結果: >>> this is a wrapped function >>> wrapped@functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
等同于partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated),不過是作為包裝函數定義時的裝飾器使用。
def wrapper(f): @wraps(f) def wrapper_function(*args, **kwargs): """this is a wrapper function""" return f(*args, **kwargs) return wrapper_function @wrapper def wrapped(): """this is a wrapped function""" pass print(wrapped.__doc__) print(wrapped.__name__)partial對象
partial對象是由partial()方法創建的可調用對象,它有三個只讀屬性:
partial.func
一個可調用對象或函數。調用partial對象將使用新的位置參數和關鍵字參數轉發到func。
partial.args
調用partial()時提供的位置參數
partial.keywords
調用partial()時提供的關鍵字參數
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/45040.html
摘要:函數內省的內容到此結束。函數式編程并不是一個函數式編程語言,但通過和等包的支持,也可以寫出函數式風格的代碼。 《流暢的Python》筆記。本篇主要講述Python中函數的進階內容。包括函數和對象的關系,函數內省,Python中的函數式編程。 1. 前言 本片首先介紹函數和對象的關系;隨后介紹函數和可調用對象的關系,以及函數內省。函數內省這部分會涉及很多與IDE和框架相關的東西,如果平時...
摘要:變量查找規則在中一個變量的查找順序是局部環境,閉包,全局,內建閉包引用了自由變量的函數。閉包的作用閉包的最大特點是可以將父函數的變量與內部函數綁定,并返回綁定變量后的函數,此時即便生成閉包的環境父函數已經釋放,閉包仍然存在。 導語:本文章記錄了本人在學習Python基礎之函數篇的重點知識及個人心得,打算入門Python的朋友們可以來一起學習并交流。 本文重點: 1、掌握裝飾器的本質、功...
摘要:看一個簡單的例子在實際實驗中,加不加并沒有區別。僅作了解這是個有趣的裝飾器,傳入的參數被打上了,當下一次傳入的參數是一樣的時候,就會從中直接取出對應的值,而不需要進行重新的運算。這樣做的好處是可以幫助我們分離代碼邏輯輸出 functools functools 包含了用于創建裝飾函數,啟動面向切面的編程,超出面向對象編程范圍的代碼復用,同時提供了裝飾函數用于豐富的快捷比較的API, p...
摘要:本文重點了解函數在中是一等對象了解中的可調用對象掌握正確定義函數參數的方法了解和中支持函數式編程的方法。歸約函數定義能夠接受一個可迭代對象并返回單個結果的函數是歸約函數。 導語:本文章記錄了本人在學習Python基礎之函數篇的重點知識及個人心得,打算入門Python的朋友們可以來一起學習并交流。 本文重點: 1、了解函數在Python中是一等對象;2、了解Python中的可調用對象;3...
摘要:本文重點了解函數在中是一等對象了解中的可調用對象掌握正確定義函數參數的方法了解和中支持函數式編程的方法。歸約函數定義能夠接受一個可迭代對象并返回單個結果的函數是歸約函數。 本文章記錄了本人在學習Python基礎之函數篇的重點知識及個人心得,歡迎打算入門Python的朋友與我一起學習交流。。 本文重點: 1、了解函數在Python中是一等對象;2、了解Python中的可調用對象;3、掌握...
閱讀 2452·2021-11-22 09:34
閱讀 3063·2021-10-25 09:43
閱讀 1975·2021-10-11 10:59
閱讀 3361·2021-09-22 15:13
閱讀 2324·2021-09-04 16:40
閱讀 418·2019-08-30 15:53
閱讀 3186·2019-08-30 11:13
閱讀 2602·2019-08-29 17:30