Python中lambda的使用,與它的三個好基友介紹!

匿名函數lambda

除了def語句,python還提供了一種生成函數對象的表達式形式。由於它與LISP語言中的一個工具類似,所以稱為lambda。

就像def一樣,這個表達式創建了一個之後能夠調用的函數,但是它返回一個函數而不是將這個函數賦值給一個變量。這些就是lambda叫做匿名函數的原因。實際上,他常常以一種行內進行函數定義的方式使用,或者用作推遲執行一些代碼。

lambda的一般形式是關鍵字lambda之後跟着一個或多個參數(與一個def頭部內用括號括起來的參數列表類似),緊跟着是一個冒號,之後是表達式

lambda arg1,arg2,argn:expression using arguments

由lambda表達式所返回的函數對象與由def創建並複製后的函數對象工作起來是完全一致的,但lambda有一些不同之處,讓其扮演特定的角色時更有用:

lambda是一個表達式,而不是一個語句

因為這一點,lambda可以出現在python語法不允許def出現的地方。
此外,作為一個表達式,lambda返回一個值(一個新的函數),可以選擇性的賦值給一個變量
相反,def語句總是得在頭部將一個新的函數賦值給一個變量,而不是將這個函數作為結果返回。

lambda的主題是單個表達式,而不是一個代碼塊

這個lambda的主題簡單的就好像放在def主體return語句中的代碼一樣。
簡單的將結果寫成一個順暢的表達式,而不是明確的返回。
但由於它僅限於表達式,故lambda通常要比def功能少…你僅能夠在lambda主體中封裝有限的邏輯進去,因為他是一個為編寫簡單函數而設計的。
除了上述這些差別,def和lambda都能過做同樣種類的工作

def與lambda的相同用法

x = lambda x, y, z: x + y + z
x(2, 3, 4)
>>> 9

y = (lambda a='hello', b='world': a + b)
y(b='Python')
>>> 'hellopython'

為什麼使用lambda

看過上面的兩個小例子,很多人會說這個和def沒什麼差別,我們又為什麼要使用lambda呢?

通常來說,lambda起到一種函數的速寫作用,允許在使用的代碼內嵌一個函數的定義,他完全是可選的(是可以使用def代替他們),但是在你僅需要切入一段可執行代碼的情況下,它會帶來一個更簡潔的書寫效果。

lambda通常用來編寫跳轉表,也就是行為的列表或者字典,能夠按照需求執行操作,比如:

l = [lambda x: x ** 2, lambda x: x ** 3, lambda x: x ** 4]
for f in l:
    print(f(2))
>>> 4
>>> 8
>>> 16
print(l[0](3))
>>> 9

當需要把小段的可執行代碼編寫進def語句從語法上不能實現的地方是,lambda表達式作為def的一種速寫來說,是最為有用的,如果上面的代碼用def編寫,則變為:

def f1(x):
    return x ** 2
 
def f2(x):
    return x ** 3
 
def f3(x):
    return x ** 4
 
l = [f1, f2, f3]

for f in l:
    print(f(2))
print(l[0](3))

實際上,我們可以用python中的字典或者其他的數據結構來構建更多種類的行為表,從而做同樣的事情。

lambda中實現if-else

Python中具備的單行表達式:if a:b else c語法在lambda中同樣適用:

lower = lambda x,y:x if x<y else y
lower(4,5)
>>> 4

看了半天,大家可能也並未覺得lambda在python中到底比def優越與便利在哪裡,那麼說到lambda,就必須要提及三個函數map、filter、reduce,當你接觸了這三個函數,那麼你才能感受到lambda真實的方便之處

map 函數

程序對列表或者其他序列常常要做的一件事就是對每個元素進行一個操作,並把其結果集合起來。
python提供了一個工具map,它會對一個序列對象中的每一個元素應用該的函數,並返回一個包含了所有函數調用結果的列表。

舉個栗子,我們有一個列表,需要將列表的每一個字段+10,我們該如何操作?

list_show = [1, 2, 3, 4]
# 方式1
new_list_show = []
for i in list_show:
    new_list_show.append(i + 10)

print(new_list_show)

# 方式2
def adds(x):
    return x + 10

print(list(map(adds, list_show)))

# 更優雅的方式3:
print(list(map(lambda x: x + 10, list_show)))

看看上面三個實現方式,你覺得那種更加Pythonic?

eg:需要注意一點,map在python3中是一個可迭代對象,引入需要使用列表調用來使它生成所有的結果用於显示,python2不必如此。

當然map的闡述函數,不僅僅支持自己編寫的,同樣也支持python自帶的多種函數,比如:

list_show = [1, -2, 3, -4, 5, -6]
print(list(map(abs, list_show)))
>>> [1, 2, 3, 4, 5, 6]

filter函數

filter通過字面意思,大家就知道它的用處了,用於數據的過濾操作,它也是lambda的一個好基友,舉個栗子。
我們需要過濾0-9中,能被2整除的数字組成一個列表,我們該如何操作?只需要一行代碼:

print(list(filter(lambda x: x % 2 == 0, range(10))))
>>> [0, 2, 4, 6, 8]

沒錯,filter就是這麼的簡單實用….

reduce的妙用

reduce在python2中是一個簡單的函數,但在python3中它責備收錄與functools中。
它接收一個迭代器來處理並返回一個單個的結果。

list_show = [1, 2, 3, 4]
print(reduce(lambda x, y: x + y, list_show))
>>> 10
print(reduce(lambda x, y: x * y, list_show))
>>> 24

lambda的實用與它的好基友就介紹到這裏,希望對大家有所幫助。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

3c收購,鏡頭 收購有可能以全新價回收嗎?

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

賣IPHONE,iPhone回收,舊換新!教你怎麼賣才划算?

GDG Xi’an DevFest 2019 閃電演講 -《假如我是一個瀏覽器》PPT(經典多圖,建議收藏)

GDG Xi’an DevFest2019演講PPT鏈接:

閃電演講《假如我是一個瀏覽器》PPT鏈接:

關於我的一篇雞湯文,獻給所有努力中的野生前端:

摘要

內容講述了HTML,CSS和JavaScript文件從代碼到瀏覽器中圖形的基本過程,實際上每個階段正好代表了高級前端工程師可以選擇的三大細分方向——架構師,工程化,圖形學。PPT基本上全是圖,引用了一些知名的前端神圖,大部分都是自己一點點做的,畢竟圖的表現力比文字要生動直觀一些,原稿幾乎每一頁都加了備註!!!,有需要的可以在我的博客或者GDG西安官方公眾號獲取到。

作者簡介

請求階段

請求階段從解析DNS開始,它是一個遞歸的過程,可以在Linux系統中使用dig+trace工具進行追蹤查看;查詢到地址后就需要開始建立連接(三次握手建立連接),然後從服務器獲取第一個文件,通常是index.html,獲取到文件后就需要根據響應頭裡的信息進行一些處理,對這塊不太熟悉的同學可以閱讀《圖解Http》一書,強制緩存和協商緩存這一塊是很重要的考點,index.html在解析時可能還會碰到請求其他資源的情況,這時又會引出CDN等等其他話題,本次分享中並未涉及。如果對於前端可用性及資源部署方面感興趣,可以考慮向架構師的方向發展,也就是只將前端應用視為整個鏈路中的一環,嘗試去關注整個鏈路中各個環節,前端工程師切入時並不需要特別關注去解決細枝末節的技術問題,那畢竟需要時間和經驗的積累,請記住你是有夥伴的,我個人比較推薦前端工程師嘗試建設全鏈路的異常監控體系,去了解各個環節有哪些關鍵指標,如何去呈現,如何去判斷異常等等,以盡可能穩定有效的方式把關鍵信息呈現給能解決問題的人。

解析階段

我在分享時已經提及過,解析階段的關鍵詞就是“編譯原理”,前端基礎的HTML,CSS,JS,以及常見的工程化工具例如Webpack,Babel,Eslint等等,全部都是基於編譯原理來運作的,如果從純學術的角度來看,它的確很晦澀,但是從應用的角度來理解,實際上無論是分詞,轉換還是遍歷AST以及最終的代碼生成,實際上都是看得見摸得着的,並不算特別難理解,B站上有很多國內外的《編譯原理》課程錄像,你懂的(B站真的是學習用的)。其中還涉及到了一些基本的數據結構和基礎算法的知識,這裏的知識是對基本功的硬考驗,也就是“設計模式”“數據結構”和“基礎算法”的三座大山,爬山很慢,但真的很值。這一塊的知識可以翻看朱永盛的《Webkit技術內幕》一書,慎重,沒有老司機帶的話這本書很容易看的人懷疑人生。

種樹階段

種樹階段只是戲稱,就是為了不同的目的構建了許許多多的樹和層。HTML解析後生成DOM樹,它表示文檔的結構,CSS在內部優化時也會生成樹,為了將用於渲染的信息整合在一起,兩者被合併生成了RenderObject樹,為了解決層疊順序問題,又在此基礎上生成了RenderLayer層,為了利用硬件加速渲染,又為滿足另一些條件的層生成CompositingLayer合成層,合成層又使用GraphicsLayer來進行後端存儲。概念之多,相對複雜。為了排除干擾,本次分享中並沒有講述Chrome瀏覽器的多進程模型和多線程結構,它們只是為了更好更高效地處理好關鍵渲染步驟,一次性信息量太大反而會影響吸收。

畫畫階段

畫畫階段實際上是指將對象信息通過光柵化處理后得到位圖信息並展示在显示器上的過程,PPT中並沒有涉及,它涉及到很多圖形學相關的知識,基本的WebGL以及Chromium渲染管線方面的知識。對此感興趣的讀者可以掃描下面的二維碼關注我技術博客中系列博文,比較詳細地描述了這部分相關知識。最後提一下,原稿最後一頁的資料在播放模式下都可以直接點擊跳轉,還有每一頁的備註信息如果看不見可能需要手動把畫面向上拖拽縮小一點。

硬廣時間

我的博文集《大史住在大前端》是關於前端基礎的文章,掃下面右邊的二維碼就可以看到,基本都是系列專題,沒有太多關於三大框架或是熱門技術的東西,都是基礎基礎基礎,或許會對你有幫助。最後再次感謝GDGXi’an提供的這次機會,讓我認識了好多好多優秀的大佬和開發者。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

3c收購,鏡頭 收購有可能以全新價回收嗎?

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

賣IPHONE,iPhone回收,舊換新!教你怎麼賣才划算?

【python測試開發棧】python內存管理機制(一)—引用計數

什麼是內存

在開始進入正題之前,我們先來回憶下,計算機基礎原理的知識,為什麼需要內存。我們都知道計算機的CPU相當於人類的大腦,其運算速度非常的快,而我們平時寫的數據,比如:文檔、代碼等都是存儲在磁盤上的。磁盤的存取速度完全不能匹配cpu的運算速度,因此就需要一个中間層來適配兩者的不對等,內存由此而來,內存的存取速率很快,但是存儲空間不大。

舉一個圖書館的例子,便於大家理解,我們圖書館的書架就相當於磁盤,存放了大量的圖書可以供我們閱讀,但是如果書放在書架上,我們沒辦法直接閱讀(效率低),只能將書取出來,放在書桌上看,那書桌就相當於內存。

內存回收

內存資源畢竟是有限的,所以在使用之後,必須被回收掉,否則系統運行一段時間后就會因無內存可用而癱瘓。我們軟件測試領域常用的兩種語言:java和python,全部都採用內存自動回收的方法,也就是我們只管申請內存,但是不管釋放內存,由jvm和python解釋器來定期觸發內存回收。作為對比,C語言和C++中,程序員需要使用malloc申請內存,使用free去釋放內存,malloc和free必須成對的出現,否則非常容易出現內存問題。

還拿上面圖書館的例子,假如圖書館的書看完之後放在書桌上就可以(因為圖書可自動回收),那麼很快的,就沒有位置給新進來的同學看書了。這時候就需要圖書館管理員(jvm或python解釋器)定期的回收圖書,清空書桌。不過正常情況下,我們離開圖書館時,要自己清空書桌,將書放回書架(類似C語言和C++的內存回收方式)。

python內存管理

引用計數

python通過引用計數來進行內存管理,每一個python對象,都維護了一個指向該對象的引用計數。python的sys庫提供了getrefcount()函數來獲取對象的引用計數。下面我們看個例子(注意:不同版本的python,運行結果不同,我這裏採用的是python3.7.4):

"""
    @author: xuanke
    @time: 2019/11/27
    @function: 測試python內存
"""
import sys

class RefClass(object):
    def __init__(self):
        print("this is init")

def ref_count_test():
    # 驗證普通字符串
    str1 = "abc"
    print(sys.getrefcount(str1))
    # 驗證稍微複雜點的字符串
    print(sys.getrefcount("xuankeTester"))
    # 驗證小的数字
    print(sys.getrefcount(12))
    # 驗證大的数字
    print(sys.getrefcount(257))
    # 驗證類
    a = RefClass()
    print(sys.getrefcount(a))
    # 驗證引用計數增加
    b = a
    print(sys.getrefcount(a))

    # 驗證引用計數減少
    b = None
    print(sys.getrefcount(a))

if __name__ == '__main__':
    ref_count_test()

大家先來思考下,最終的結果會是什麼?!我覺得應該很多人都會答錯,因為不同版本的python,對引用變量個數有影響(主要是可復用的對象)。我們先貼出來運行結果,再來分析產生結果的原因:

27
4
9
3
this is init
2
3
2

不過提前聲明一點:sys.getrefcount函數在使用時,因為將對象(比如上例中的str1)作為參數傳入,所以會額外增加一個變量(相當於getrefcount持有了str1的引用),因此實際每個對象的實際引用計數都得減1。下面分別介紹下上面的幾種情況:

  • 字符串: str1=’abc’的引用數是27-1=26,是因為字符串’abc’比較簡單,在python解釋器(CPython)中確實可能存在26個引用。作為對比,在python2.7中,str1的引用變量個數是3-1=2。而字符串’xuanketester’,是我自定義的一個字符串,所以不可能會有其他額外的引用,所以其引用變量個數是3-1=2(至於為什麼是2,理論應該是0,是因為python解釋器默認持有了所有字符串的兩個引用)。
  • 数字: 数字12對應的引用計數個數是9-1=8,而257對應的引用計數個數是3-1=2,這主要是因為,在python初始化過程中,就創建了從-5到256的数字,緩存起來,這樣做是為了頻繁的分配內存,提高效率。而對於不在這個區間的数字,則會重新分配內存空間。所以数字12因為被複用,其引用計數個數是8(在python2.7.14中,其引用計數個數是8)。
  • 類: 在上面例子中,創建一個RefClass對象,其引用計數就是2-1=1,因為其是一個我們自定義的類對象,在python解釋器(Cpython)中肯定不會被複用。

我們可以通過打印內存地址的方式來驗證上面這幾種情況:

    def memory_address_test():
    str1 = 'xuankeTester'
    str2 = 'xuankeTester'
    print(id(str1))
    print(id(str2))

    str3 = 'abc'
    str4 = 'abc'
    print(id(str3))
    print(id(str4))

    a = 12
    b = 12
    print(id(a))
    print(id(b))

    c = 257
    d = 257
    print(id(c))
    print(id(d))

按照我們上面的分析,c和d的地址應該是不一樣的,a和b的地址是一樣的,字符串str1和str2、str3和str4內存地址都是一樣的。但是我在pycharm中,直接運行py文件,結果卻和預想的不一致,結果如下:

2854496960176
2854496960176
2854496857840
2854496857840
140724423258720
140724423258720
2854498931120
2854498931120

所有情況的內存地址都是一樣的,這是為什麼呢?我考慮到是不是pycharm對py文件做了優化,於是我又在命令行嘗試執行,結果還是一樣的。所以,我猜測可能是python解釋器在執行文件時,為了提高py文件的執行效率,對文件的內存地址做了優化—相同內容的對象內存地址都一樣。

為了驗證這個想法,我直接在python交互模式下執行,果然得到了我想要的結果:

Python 3.7.4 (tags/v3.7.4:e09359112e, Jul  8 2019, 20:34:20) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> a=12
>>> b=12
>>> id(a)
140724423258720
>>> id(b)
140724423258720
>>> a=257
>>> b=257
>>> id(a)
2559155778384
>>> id(b)
2559155778192
>>> a='xuankeTester'
>>> b='xuankeTester'
>>> id(a)
2559155711280
>>> id(b)
2559155711280
>>>

從上面可以看到兩個257對應的地址確實是不一樣的,和我們最初判斷的是一致的。

總結

python通過對象的引用計數來管理內存,其實java的JVM也有用引用計數,所以理解了引用計數,為我們理解python的垃圾回收方法打下了基礎。本計劃這一篇文章就將python內存管理的機制講完的,但是發現一個內存引用計數就有很多東西得寫,所以索性就分兩篇文章來寫,之後再寫一篇文章來介紹python的垃圾回收方式。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

3c收購,鏡頭 收購有可能以全新價回收嗎?

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

賣IPHONE,iPhone回收,舊換新!教你怎麼賣才划算?

JavaScript 是否應該重命名

  在誕生 25 年之後,JavaScript 語言仍然讓很多人困惑不已。所以一個老生常談的問題是:它是否應該重命名?呼籲改名的支持者列舉了一系列理由,包括:

  • JavaScript 本意指的是 ECMAScript 的子集,但使用中它經常被指代多種不同的 ECMAScript 超集
  • JavaScript 是甲骨文公司的商標,這與 JavaScript 作為 Web 平台核心組件的身份不相符合,Web 平台是建立在開放技術和標準基礎上的
  • JavaScript 連官方 logo 都沒有
  • JavaScript 與 Java 沒有一點關係,幾十年來它給非技術人員造成了混淆。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

3c收購,鏡頭 收購有可能以全新價回收嗎?

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

賣IPHONE,iPhone回收,舊換新!教你怎麼賣才划算?