概覽
????函數(shù)在python里是作為第一類對象(First Class Objects)囱皿。在編程語言理論里勇婴,定義一個“第一類對象”作為編程對象能夠做到以下幾點(diǎn):
- 在運(yùn)行時創(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ù)賦值給一個對象齿兔,并且使用這個對象的名字調(diào)用函數(shù)橱脸。也可以把函數(shù)作為參數(shù)傳遞給另一個函數(shù)础米。
Higher-Order Functions
????一個函數(shù)把函數(shù)作為參數(shù)或者把函數(shù)作為返回結(jié)果就被稱為高階函數(shù)(high-order function)。
????函數(shù)式編程通常提供一些通用的高階函數(shù)如map
慰技,reduce
椭盏,filter
等。不過在python里由于list comprehensions還有g(shù)enerator expressions的引入吻商,都不太重要了掏颊。在python3里map
和filter
返回生成器,而在python2里返回list艾帐。在python3里reduce
被從built-in里移除乌叶,放在了functools模塊里。
Anonymous Functions
????在使用高階函數(shù)時柒爸,有時候創(chuàng)建一個小的准浴,一次性的函數(shù)會很方便,這個就是匿名函數(shù)的由來捎稚。
????匿名函數(shù)是由lambda
關(guān)鍵字創(chuàng)建乐横。不過由于匿名函數(shù)句法的局限,匿名函數(shù)的函數(shù)體只能是純表達(dá)式今野。除了作為高階函數(shù)的參數(shù)以為葡公,匿名函數(shù)的使用場景非常有限。
The Seven Flavors of Callable Objects
????call
操作符(就是())除了用戶自定義函數(shù)以外条霜,也可以用在其他對象上催什。要確定一個函數(shù)是否是callable的,可以使用內(nèi)建的callable() 函數(shù)宰睡。python定義了七種callable類型:
- User-defined functions:使用def語句或者用lambda表達(dá)式創(chuàng)建蒲凶。
- Built-in functions:使用C實現(xiàn)的函數(shù),如len拆内。
- Built-in methods:使用C實現(xiàn)的方法旋圆,如dict.get。
- Methods:定義在類里的函數(shù)麸恍。
- Classes:調(diào)用類就是創(chuàng)建一個實例臂聋。
- Class instances:類如果定義了
__call__
方法,那么類的實例也可以像函數(shù)一樣調(diào)用或南。 - Generator functions:使用
yield
關(guān)鍵字的函數(shù)或方法孩等。
User-Defined Callable Types
????這一節(jié)介紹的就是7種callabe類型里的第6種。主要使用的場景就是創(chuàng)建在調(diào)用時需要保存內(nèi)部狀態(tài)的像函數(shù)一樣的對象采够,另一種方式就是閉包(Closures)癣防,后面會詳細(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)用一個函數(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ù)捕獲蝴罪。要定義一個僅限關(guān)鍵字參數(shù),就把他放在前綴的參數(shù)后面步清。如果不需要變化的參數(shù)要门,但是還需要僅限關(guān)鍵字參數(shù),那么就直接放在的后面廓啊。
Retrieving Information About Parameters
????函數(shù)對象有幾個內(nèi)省的屬性存儲了參數(shù)信息:
-
__defaults__
:存儲了參數(shù)的默認(rèn)值 -
__kwdefaults__
:存儲了keyword-only參數(shù)的默認(rèn)值 -
__code__
:__code__.co_varnames
存儲了參數(shù)名和局部變量的名字欢搜,通過__code__.co_argcount
定位前N個作為參數(shù)。
????更簡單的是使用inspect.signature
來獲取參數(shù)信息谴轮。
Function Annotations
????python3提供了語法給函數(shù)的參數(shù)和返回值附加一些元數(shù)據(jù)炒瘟。如類型還有限制條件,不過現(xiàn)在python只是做了些記錄第步,并沒有去做檢查疮装。
Packages for Functional Programming
????operator包里包含了很多算術(shù)操作符,另外幾個比較有用的函數(shù)itemgetter
粘都,attrgetter
斩个,methodcaller
。
????functools包里主要介紹了partial驯杜,可以用來生成一個新的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