一個 lambda 表達式引發的思考

一個 lambda表達式 引發的思考

 
 
 
 
 

全文都是抄來的html

1. 列表生成式

1.1 range 函數:

 
 
 
 
 

1.2 列表生成式:

 
 
 
 
 

2. 匿名函數: 原文連接

Python中的lambda的「一個語法,三個特性,四個用法,一個爭論」。python

一個語法

在Python中,lambda的語法是惟一的。其形式以下:web

 
 
 
 
 

其中,lambda是Python預留的關鍵字,argument_list和expression由用戶自定義。具體介紹以下。express

  1. 這裏的argument_list是參數列表。它的結構與Python中函數(function)的參數列表是同樣的。具體來講,argument_list能夠有很是多的形式。例如:
  • a, b
  • a=1, b=2
  • *args
  • **kwargs
  • a, b=1, *args
  • ......

這裏的expression是一個關於參數的表達式。表達式中出現的參數須要在argument_list中有定義,而且表達式只能是單行的。如下都是合法的表達式:編程

  • 1
  • None
  • a + b
  • sum(a)
  • 1 if a >10 else 0
  • ......

這裏的 lambda argument_list: expression 表示的是一個函數。這個函數叫作lambda函數。api

 

三個特性

lambda函數有以下特性:閉包

 
 
 
 
 

下面是一些lambda函數示例:app

 
 
 
 
 

 

四個用法

因爲lambda語法是固定的,其本質上只有一種用法,那就是定義一個lambda函數。在實際中,根據這個lambda函數應用場景的不一樣,能夠將lambda函數的用法擴展爲如下幾種:函數

  1. 將lambda函數賦值給一個變量,經過這個變量間接調用該lambda函數。學習

       
       
       
       
       
  1. 將lambda函數賦值給其餘函數,從而將其餘函數用該lambda函數替換。

       
       
       
       
       
  2. 將lambda函數做爲其餘函數的返回值,返回給調用者。

       
       
       
       
       
  1. 將lambda函數做爲參數傳遞給其餘函數。
 
 
 
 
 
  1. 另外,部分Python庫函數也接收函數做爲參數,例如 gevent 的 spawn 函數。此時,lambda 函數也可以做爲參數傳入。

3. 閉包 原文連接

1.什麼是閉包,閉包必須知足如下3個條件:

  • 必須是一個嵌套的函數。
  • 閉包必須返回嵌套函數。
  • 嵌套函數必須引用一個外部的非全局的局部自由變量。

舉個栗子

 
 
 
 
 

2.閉包優勢

  • 避免使用全局變量
  • 能夠提供部分數據的隱藏
  • 能夠提供更優雅的面向對象實現

優勢1,2 就不說了,很容易理解,關於第三個,例如當在一個類中實現的方法不多時,或者僅有一個方法時,就能夠選擇使用閉包。

舉個栗子

 
 
 
 
 

閉包的概念差很少就是這樣了。

 

4. 延遲綁定:

 
 
 
 
 

 

5. 解決問題 原文連接

1、問題描述

 
 
 
 
 

上述式子的輸出結果: 預計結果爲:0, 2, 4, 6 實際輸出爲:3, 3, 3, 3

  • 原理:i 在外層做用域 lambda x: x*i 爲內層(嵌)函數,他的命名空間中只有 {'x': 1} 沒有 i , 因此運行時會向外層函數(這兒是列表解析式函數 [ ])的命名空間中請求 i 而當列表解析式運行時,列表解析式命名空間中的 i 通過循環依次變化爲 0-->1-->2-->3 最後固定爲 3 , 因此當 lambda x: x*i 內層函數運行時,去外層函數取 i 每次都只能取到 3
  • 解決辦法:變閉包做用域爲局部做用域。 給內層函數 lambda x: x*i 增長參數,命名空間中有了用來存儲每次的 i , 即改爲 [lambda x, i=i: x*i for i in range(4)] 這樣每一次,內部循環生成一個lambda 函數時, 都會把 --i--做爲默認參數傳入lambda的命名空間 循環4次實際lambda表達式爲: 第一次:lambda x, i=0 第二次:lambda x, i=1 第三次:lambda x, i=2 第四次:lambda x, i=3
 
 
 
 
 

2、上面看不懂就看這兒

函數fun = [lambda x: x*i for i in range(4)]等價於:以下函數

 
 
 
 
 

查看該函數命名空間及 I 值變化:

 
 
 
 
 

#運行結果爲:爲了排版美觀,我已將輸出lambda_函數地址更名爲:lam函數1 2 3

 
 
 
 
 

能夠看見:就像上面所說的:四次循環中外層函數命名空間中的 i 從 0-->1-->2-->3 最後固定爲3, 而在此過程當中內嵌函數-Lambda函數中由於沒有定義 i 因此只有Lambda 函數動態運行時, 在本身命名空間中找不到 i 纔去外層函數複製 i = 3 過來,結果就是全部lambda函數的 i 都爲 3, 致使得不到預計輸出結果:0,1,2,3 只能獲得 3, 3, 3, 3

  • 解決辦法:變閉包做用域爲局部做用域。
 
 
 
 
 

給內層函數 lambda增長默認參數,命名空間中有了用來存儲每次的 i , 即改爲 `def lambda(x, i=i) :` 這樣每一次, 內部循環生成一個lambda 函數時,都會把 i 做爲默認參數傳入lambda的命名空間 循環4次實際lambda表達式爲: 第一次:lambda( x, i=0) 第二次:lambda(x, i=1) 第三次:lambda(x, i=2) 第四次:lambda(x, i=3)

這樣咱們就能獲得預計的結果:0, 1, 2, 3

5. LEGB

只有函數、類、模塊會產生做用域,代碼塊不會產生做用域。做用域按照變量的定義位置能夠劃分爲4類:

 
 
 
 
 

python解釋器查找變量時,會按照順序依次查找局部做用域--->嵌套做用域--->全局做用域--->內建做用域,在任意一個做用域中找到變量則中止查找,全部做用域查找完成沒有找到對應的變量,則拋出 NameError: name 'xxxx' is not defined的異常。

人生還有意義。那必定是還在找存在的理由

相關文章
相關標籤/搜索