Python函數式編程

来源:https://www.cnblogs.com/ZJiQi/archive/2018/04/14/8825778.html
-Advertisement-
Play Games

Python函數式編程 TOC + 函數參數中的魔法 + 位置參數 + 預設參數 + 動態參數 + 位置參數收集 + 關鍵字參數收集 + 收集參數行為的逆向過程(這個逆向過程用於實參上) + 參數傳遞 + 函數嵌套 + 命名空間 + 作用域 + 閉包 + 函數式編程 + 裝飾器 + 顯示方式 + @ ...


Python函數式編程

TOC

  • 函數參數中的魔法
    • 位置參數
    • 預設參數
    • 動態參數
      • 位置參數收集
      • 關鍵字參數收集
      • 收集參數行為的逆向過程(這個逆向過程用於實參上)
    • 參數傳遞
  • 函數嵌套
    • 命名空間
    • 作用域
    • 閉包
    • 函數式編程
  • 裝飾器
    • 顯示方式
    • @方式
    • 帶參數裝飾器
    • functools.wraps(func)
  • 匿名函數
  • 高階函數
    • 三劍客
      • filter()
      • map()
      • reduce()
    • sorted()
  • 遞歸函數

函數參數中的魔法

coming...

嵌套函數

顧名思義就是一個函數定義中嵌套了一個函數的定義。說道嵌套函數,就必須先介紹命名空間和作用域

命名空間NameSpace

python分三類命名空間。內置,全局,本地。包括一個區域,封閉區域。

  • Builtins 內置空間,在main模塊載入前創建
  • Globals 全局空間,模塊為單位。包空間其實是__init__.py模塊
  • Enclosing 封閉區域
  • Locals 本地空間,函數,類,對象等
作用域Scope

python對象的作用域是遵照LEGB規則。

閉包

一般普通的函數嵌套並沒什麼特別的用處。但是嵌套函數有個突出的應用,也是非常強大的應用。就是,通過外層函數創建一個函數,即返回內層函數,外層函數每一調用返回的內層函數,這些返回的內層函數之間是獨立的函數對象。他們都“繼承”了外層函數調用時的作用域。這個“繼承”行為我們稱為閉包。

閉包顯著的特點就是:返回的內層函數中,使用了外層函數的局部變數或者參數參與內層函數的運算。這些變數和參數的值還是外部函數調用返回前時的值。
要註意的是:返回內層函數時,使用外層函數時的變數或者參數,如果在返回後發生了變化。那麼內層函數後面調用會使用變化後的值,而不是返回內層函數那個時間點的值了。所以很多博客都在強調,閉包返回的內層函數不要引用還會在外層函數發生變化的變數。
要解決這個問題,可以採取中間變數(中間變數就是固定的了)或者再嵌套一個中間函數,讓這個中間函數來獲取變化的變數,在傳遞給最內層的函數,並返回最內層的函數。

記住:內層函數返回時是不會執行的。

__自己猜想__
有點類似於面向對象,一個對象方法返回另一個對象,新對象的實例化是受到返回它的對象影響,展現除了多態的特性。閉包有點多態,繼承,封裝(函數本來就是一種封裝形式)的意思,將規律相似的作為一層。多層次之間可以看作多層次的嵌套函數來設計,能產生“繼承變數”的哪一層就作為上層,有幾層規律就嵌套幾層函數,從外到內,每一層都是和上一層有一個或多個“繼承變數”關係。算一種設計範式了吧。
如:乘法運算,將第一個乘數作為一層,第二乘數提供後算出乘積來作為第二層。那麼就可以使用閉包將拆分有關係的兩層進行程式設計。
再如:裝飾器函數的inner()函數,就是要繼承裝飾函數說傳遞的參數。返回的inner函數調用就會間接調用被裝飾的函數。inner函數實現了擴展需求的功能。
找點裝飾器或者其它閉包例子來佐證猜想
函數式編程

摘自廖雪峰python教程

函數式編程是一種抽象程度很高的編程範式,純粹的函數式編程語言編寫的函數是沒有變數的,因此,任意一個函數,只要輸入是確定的,輸出就是確定的,這種純函數我們稱之為沒有副作用。而允許使用變數的程式設計語言,由於函數內部的變數狀態不確定,同樣的輸入,可能得到不同的輸出,因此這種函數是有副作用的。
函數式編程的一個特點就是,允許把函數本身作為參數傳入另一個函數,還允許返回一個函數!
python 對函數式編程提供部分支持。由於Python允許使用變數,因此Python不是純函數式編程語言。

裝飾器Decorator

裝飾器是函數式編程的集大成應用。涉及高階函數,閉包,參數傳遞等。
如果只是要擴展功能,只需要再創建一個函數,並嵌套需要擴展的函數,就是在創建的函數中實現擴展功能後,再執行擴展前的函數就可以了。但是這樣做有一個缺點就是,原函數名被改變了,這樣會被調用原函數的其它部門打死的,你這樣方便了自己卻麻煩了其他人。
那就要想辦法呀,那重命名這個擴展的函數為原函數名呢?肯定不行,這樣函數調用就編程了遞歸函數了。
那就這樣設計:用一個函數返回一個函數,返回的函數重命名為原來的函數名。調用這個重命名返回函數,就是執行擴展後再調用原函數。這就是通過閉包,實現裝飾器。

  • 裝飾外層函數:返回內層函數
  • 裝飾內層函數:實現原功能上的“封閉-開發”原則的擴展功能。內層函數對擴展功能實現後,再調用原函數,並return原函數調用返回值。
顯示方式
# 我們已一個廖老師裝飾器思考題為例,說明兩種方式表示裝飾器的應用
# 題目:請設計一個decorator,它可作用於任何函數上,並列印該函數的執行時間
import time

def runtime(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        res = func(*args, **kwargs)
        t2 = time.time()
        print((t2-t1))
        return res
    return wrapper

def get_sum(*args):
    sums = 0
    for i in args:
        sums += i
    return sums

get_sum = runtime(get_sum)  # 這就是顯示方式
print(get_sum(*list(range(10000))))
@方式
# 裝飾器函數一樣
import time

def runtime(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        res = func(*args, **kwargs)
        t2 = time.time()
        print((t2-t1))
        return res
    return wrapper

@runtime  # 這裡就是@方式,等價於上面的 顯示方式 
def get_sum(*args):
    sums = 0
    for i in args:
        sums += i
    return sums

print(get_sum(*list(range(10000))))

結果:

0.0010001659393310547 #運行時間
49995000 #函數返回值

使用裝飾器擴展的功能變得更具相容性,高內聚。(帶參數裝飾器)

什麼意思呢?翻譯成‘人話’就是:一般裝飾器只擴展一類相似功能的一種,現在要給這一功能提供並傳遞參數,是裝飾器展現出不同的行為。
裝飾器帶上參數,只需要再裝飾器包裹一個函數,這個函數接收參數,返回一個外層裝飾器函數,內層函數接受到包裹的哪層函數的參數,在擴展代碼中進行應用,這樣使得擴展代碼具有更多變數,理所當然,也會拿到外層還是傳遞的原函數。內層函數拿到這兩個東西,就可以大施拳腳,做出各種功能來了。
直接代碼說話:

# 廖老師的列印調用一個函數的日誌。
def log(text):
    def outer(func):
        def inner(*args, **kwargs):
            print("%s begin call " % text)
            return func(*args, **kwargs)
        return inner
    retrun outer

@log('求和')
def get_sum(*args):
    sums = 0
    for i in args:
        sums += i
    return sums

print(get_sum(*list(range(10000))))

運行結果:

求和 begin call # 擴展的功能:列印執行日誌
49995000 # 函數返回結果

讓裝飾器更安全

因為裝飾器的內層函數被重新綁定給了原函數名,內層函數的__name__還是內層函數名,而不是原函數名。有些依賴函數簽名的代碼可能會報錯。python的functools提供了
將內層函數的__name__值變為重新綁定到的變數的名字。
用法:

import functools
def decorator(func)
    @functools.wraps(func)  # 用在這裡,就是wrapper之前,無論帶參數還是不帶參數的裝飾器
    def wrapper(*args, **kwargs):
        pass
        return func(*args, **kwargs)
    return wrapper

裝飾器還可以不止一個參數,多個參數,多層包裹,產生多個維度。

匿名函數

匿名函數就是不需要顯示的通過def定義函數。匿名函數通常用於高階函數。匿名函數直接用於高階函數的參數或者return中,如果在return中,就形成了閉包。
關鍵字lambda 代表匿名函數
匿名函數表示方法:
lambda x, y : x + y
冒號前x, y是參數列表,冒號後面表達式的值作為函數的return值,且冒號後面只能是一個表達式,不能包含其它語句。如賦值語句,複合語句。可以使用三元表達式。
匿名函數可以縮短代碼行數。
匿名函數例子:

L = list(map(lambda *args: lambda *innerargs: print(innerargs+args),[1,2,3,4,5,6,7]))
for f in L:
    f(10)

結果:
(10, 1)
(10, 2)
(10, 3)
(10, 4)
(10, 5)
(10, 6)
(10, 7)

高階函數

什麼是高階函數?
coming...

遞歸函數

coming....


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 自從年前得空寫了兩篇文章之後就開始忙了,這一忙就是2個月
  • 系統描述:用戶與管理員客服聊天,當用戶在五分鐘之內不說話,則客服會在5分鐘後斷開。當直接關閉瀏覽器頁面時,後臺管理員就無法檢測到這種狀態,此用戶無法從管理員的服務列表裡面清除 onunload和onbeforeunload這兩個事件可以在瀏覽器關閉或者刷新時調用 可以在<script>腳本中通過 w ...
  • 1 1、開發環境搭建 2 1) 版本控制工具 3 svn 和 git 4 5 2) 下載安裝 nodeJS 和 npm 6 7 3) 在開發工具 (Hbuilder) 中配置 cmd 終端,通過終端安裝 Babel 編譯器 8 1.初始化項目 9 在安裝Babel之前,需要用npm init... ...
  • 鴿了鴿了,webpack源碼大垃圾,看了那麼久,感覺自己越來越渣……還是換個口味,node瞭解一下? 嘗試從express框架源碼入手,學習一下node的http模塊相關的知識。 入口文件 先從框架的主文件入手,該JS文件包含三大部分: 1、外部/工具模塊引入與屬性掛載 2、主函數定義 3、中間件的 ...
  • 本篇文章將CSS中的Box Model(盒子模型 ),包括盒子模型的幾個區域、通過DOM獲取不同的區域的寬高以及jQuery獲取盒子模型的寬高。 ...
  • 在整體架構中引入消息中間件,勢必要考慮很多因素,比如成本及收益問題,怎麼樣才能達到最優的性價比?雖然消息中間件種類繁多,但是各自都有各自的側重點,選擇合適自己、揚長避短無疑是最好的方式。 ...
  • 狀態模式是根據其狀態變化來改變對象的行為,允許對象根據內部狀態來實現不同的行為。內容類可以具有大量的內部狀態,每當調用實現時,就委托給狀態類進行處理。 作用 當一個對象的內在狀態改變時允許改變其行為,這個對象看起來像是改變了其類。狀態模式主要解決的是當控制一個對象狀態的條件表達式過於複雜時的情況。把 ...
  • 面向對象設計的七大原則 今天我們要談的原則有七大原則,即:單一職責,里氏替換,迪米特法則,依賴倒轉,介面隔離,合成/聚合原則,開放-封閉 。 1. 開閉原則(Open-Closed Principle, OCP) 定義:軟體實體應當對擴展開放,對修改關閉。這句話說得有點專業,更通俗一點講,也就是:軟 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...