《Fluent Python》讀書筆記-First-Class Functions

概覽

????函數(shù)在python里是作為第一類對象(First Class Objects)。在編程語言理論里,定義一個(gè)“第一類對象”作為編程對象能夠做到以下幾點(diǎn):

  • 在運(yùn)行時(shí)創(chuàng)建
  • 可以賦值給變量或者數(shù)據(jù)結(jié)構(gòu)里的元素
  • 能作為參數(shù)傳遞給函數(shù)
  • 可以作為函數(shù)的返回值

Treating a Function Like an Object

????在python里函數(shù)就是對象,類型是function。

>>> def factorial(n):
...     '''returns n!'''
...     return 1 if n < 2 else n * factorial(n-1)
... 
>>> factorial(10)
3628800
>>> factorial.__doc__
'returns n!'
>>> type(factorial)
<class 'function'>
>>> fact = factorial
>>> fact
<function factorial at 0x1053fcf28>
>>> fact(5)
120
>>> map(factorial, range(4))
<map object at 0x10566b160>
>>> list(map(fact, range(4)))
[1, 1, 2, 6]

????上面的例子展示了函數(shù)作為第一類對象的特性。可以把函數(shù)賦值給一個(gè)對象,并且使用這個(gè)對象的名字調(diào)用函數(shù)。也可以把函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù)。

Higher-Order Functions

????一個(gè)函數(shù)把函數(shù)作為參數(shù)或者把函數(shù)作為返回結(jié)果就被稱為高階函數(shù)(high-order function)。
????函數(shù)式編程通常提供一些通用的高階函數(shù)如mapreduce,filter等。不過在python里由于list comprehensions還有g(shù)enerator expressions的引入,都不太重要了。在python3里mapfilter返回生成器,而在python2里返回list。在python3里reduce被從built-in里移除,放在了functools模塊里。

Anonymous Functions

????在使用高階函數(shù)時(shí),有時(shí)候創(chuàng)建一個(gè)小的,一次性的函數(shù)會(huì)很方便,這個(gè)就是匿名函數(shù)的由來。
????匿名函數(shù)是由lambda關(guān)鍵字創(chuàng)建。不過由于匿名函數(shù)句法的局限,匿名函數(shù)的函數(shù)體只能是純表達(dá)式。除了作為高階函數(shù)的參數(shù)以為,匿名函數(shù)的使用場景非常有限。

The Seven Flavors of Callable Objects

????call操作符(就是())除了用戶自定義函數(shù)以外,也可以用在其他對象上。要確定一個(gè)函數(shù)是否是callable的,可以使用內(nèi)建的callable() 函數(shù)。python定義了七種callable類型:

  • User-defined functions:使用def語句或者用lambda表達(dá)式創(chuàng)建。
  • Built-in functions:使用C實(shí)現(xiàn)的函數(shù),如len。
  • Built-in methods:使用C實(shí)現(xiàn)的方法,如dict.get。
  • Methods:定義在類里的函數(shù)。
  • Classes:調(diào)用類就是創(chuàng)建一個(gè)實(shí)例。
  • Class instances:類如果定義了__call__方法,那么類的實(shí)例也可以像函數(shù)一樣調(diào)用。
  • Generator functions:使用yield關(guān)鍵字的函數(shù)或方法。

User-Defined Callable Types

????這一節(jié)介紹的就是7種callabe類型里的第6種。主要使用的場景就是創(chuàng)建在調(diào)用時(shí)需要保存內(nèi)部狀態(tài)的像函數(shù)一樣的對象,另一種方式就是閉包(Closures),后面會(huì)詳細(xì)講。

From Positional to Keyword-Only Parameters

????python函數(shù)最棒的特性就是極度靈活的參數(shù)處理方式,在python進(jìn)一步增強(qiáng)提供了僅限關(guān)鍵字參數(shù)(keyword-only)。與之相關(guān)的就是當(dāng)調(diào)用一個(gè)函數(shù)時(shí),使用*去展開iterables和mappings到不同的參數(shù)。

>>>def tag(name, *content, cls=None, **attrs): 
    """Generate one or more HTML tags""" 
    if cls is not None:
        attrs['class'] = cls 
    if attrs:
        attr_str = ''.join(' %s="%s"' % (attr, value) 
                                 for attr, value
                                 in sorted(attrs.items()))
    else:
        attr_str = ''

    if content:
        return '\n'.join('<%s%s>%s</%s>' %
                   (name, attr_str, c, name) for c in content) 
    else:
        return '<%s%s />' % (name, attr_str)
>>> tag('br')
'<br />'
>>> tag('p', 'hello')
'<p>hello</p>'
>>> print(tag('p', 'hello', 'world'))
<p>hello</p>
<p>world</p>
>>> tag('p', 'hello', id=33)
'<p id="33">hello</p>'
>>> print(tag('p', 'hello', 'world', cls='sidebar'))
<p class="sidebar">hello</p>
<p class="sidebar">world</p>
>>> tag(content='testing', name="img")
'<img content="testing" />'
>>> my_tag = {'name': 'img', 'title': 'Sunset Boulevard',
... 'src': 'sunset.jpg', 'cls': 'framed'}
>>> tag(**my_tag)
'<img class="framed" src="sunset.jpg" title="Sunset Boulevard" />'

????僅限關(guān)鍵字參數(shù)(keyword-only)是python3里的新特性。參數(shù)只能作為關(guān)鍵字參數(shù),而不能從未命名的位置參數(shù)捕獲。要定義一個(gè)僅限關(guān)鍵字參數(shù),就把他放在前綴的參數(shù)后面。如果不需要變化的參數(shù),但是還需要僅限關(guān)鍵字參數(shù),那么就直接放在的后面。

Retrieving Information About Parameters

????函數(shù)對象有幾個(gè)內(nèi)省的屬性存儲(chǔ)了參數(shù)信息:

  • __defaults__:存儲(chǔ)了參數(shù)的默認(rèn)值
  • __kwdefaults__:存儲(chǔ)了keyword-only參數(shù)的默認(rèn)值
  • __code____code__.co_varnames存儲(chǔ)了參數(shù)名和局部變量的名字,通過__code__.co_argcount定位前N個(gè)作為參數(shù)。
    ????更簡單的是使用inspect.signature來獲取參數(shù)信息。

Function Annotations

????python3提供了語法給函數(shù)的參數(shù)和返回值附加一些元數(shù)據(jù)。如類型還有限制條件,不過現(xiàn)在python只是做了些記錄,并沒有去做檢查。

Packages for Functional Programming

????operator包里包含了很多算術(shù)操作符,另外幾個(gè)比較有用的函數(shù)itemgetterattrgetter,methodcaller。
????functools包里主要介紹了partial,可以用來生成一個(gè)新的callable其中的一些參數(shù)值固定。

>>> a = range(10)
>>> from operator import itemgetter
>>> a_itemgetter = itemgetter(5, 1)
>>> a_itemgetter(a)
(5, 1)
>>> from collections import namedtuple
>>> LatLong = namedtuple('LatLong', 'lat long')
>>> latlon = LatLong(30, 140)
>>> from operator import attrgetter
>>> attr_lat = attrgetter('lat')
>>> attr_lat(latlon)
30
>>> from operator import methodcaller
>>> s = 'The time has come'
>>> upcase = methodcaller('upper')
>>> upcase(s)
'THE TIME HAS COME'
>>> from operator import mul
>>> from functools import partial
>>> triple = partial(mul, 3)
>>> triple(7)
21
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 包(lib)、模塊(module) 在Python中,存在包和模塊兩個(gè)常見概念。 模塊:編寫Python代碼的py...
    清清子衿木子水心閱讀 3,914評論 0 27
  • //Clojure入門教程: Clojure – Functional Programming for the J...
    葡萄喃喃囈語閱讀 4,056評論 0 7
  • 教程總綱:http://www.runoob.com/python/python-tutorial.html 進(jìn)階...
    健康哥哥閱讀 2,191評論 1 3
  • 老徐,今年54。 老徐是誰?可別誤會(huì),不是那個(gè)徐靜蕾,我和她沒關(guān)系。這位老徐是我媽,在31年前的那個(gè)夏天差點(diǎn)帶著還...
    ZHOULI0503閱讀 499評論 0 4
  • 前段時(shí)間深夜,突然有百種情緒沖上我腦子,我實(shí)在忍不了這種爆發(fā),打開微信和兩個(gè)最好的朋友說了些心里話。 第二天一早,...
    17133b2ced92閱讀 232評論 1 1

友情鏈接更多精彩內(nèi)容