1. 程式人生 > >閱讀筆記4:一等函數

閱讀筆記4:一等函數

定位 應用 ted 11.2 lambda函數 筆記 python range 用c語言實現

1.概述

在Python中,函數是一等對象

一等對象的定義:
在運行時創建
能賦值給變量或數據結構中的元素
能作為參數傳給函數
能作為函數的返回結果

在python中,整數,字符串和字典都是一等對象

2. 把函數視作對象

python函數是對象,是function類的實例

函數可以賦值給變量,也可以作為參數傳給其他函數

>>> def doublefunc(value):
return value * 2

>>> myfuc = doublefunc
>>> myfuc
<function doublefunc at 0x043702B8>
>>> myfuc(5)
10
>>> map(doublefunc, range(10))
<map object at 0x0436EF30>
>>> list(map(doublefunc, range(10)))
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

3.高階函數



高階函數:
接受函數作為參數,或者把函數作為結果返回的函數是高階函數, 比如 map sorted

map filter 和reduce的替代品:
列表推導替代map和filter

>>> list(map(doublefunc, range(10)))
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>> [doublefunc(n) for n in range(10)]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>> list(map(doublefunc, filter(lambda n: n%2, range(10))))
[2, 6, 10, 14, 18]
>>> [doublefunc(n) for n in range(10) if n % 2]
[2, 6, 10, 14, 18]

python2中,reduce是內置函數,在python 3放到functools模塊了。可用sum取代reduce


>>> from functools import reduce
>>> from operator import add
>>> reduce(add, range(100))
4950
>>> sum(range(100))
4950

all和any也是內置的歸約函數

all(iterable)
如果iterable的每個元素都是真值,返回True; all([])返回True

any(iterable)
只要iterable中有元素是真值,返回True; any([])返回False

4.匿名函數

python用lambda創建匿名函數
但是lambda函數的定義體只能使用純表達式;也就是說不能賦值,也不能使用while和try等python語句
>>> fruits = [‘strawberry‘, ‘apple‘, ‘cherry‘, ‘banana‘]
>>> sorted(fruits, key = lambda word: word[::-1])
[‘banana‘, ‘apple‘, ‘strawberry‘, ‘cherry‘]

除了作為參數傳給高階函數之外,python很少使用匿名函數

5.可調用對象

除了用戶定義的函數,調用運算符(即())還可應用到其他對象上;如果想判斷對象能否調用,可以使用內置的callable()函數

python中的可調用對象:
1)用戶定義的函數
使用def或lambda表達式創建
2)內置函數
使用c語言(cPython)實現的函數, 如len 或者time.strftime
3)內置方法
使用c語言實現的方法,如dict.get
4)方法
在類的定義體中定義的函數
5)類
調用類時會運行類的__new__方法創建一個實例,然後運行__init__方法,初始化實例,最後把實
例返回給調用方。因為python沒有new運算符,所以調用類就相當於調用函數
6)類的實例
如果類定義了__call__方法,那麽它的實例可以作為函數調用
7)生成器函數
使用yield關鍵字的函數或方法。調用生成器函數返回的是生成器對象

6.用戶定義的可調用類型

不僅python函數是真正的對象,任何python對象都可以表現得像函數,為此,只需要實現實例方法__call__

import random
class BingoCage:
   def __init__(self, items):
      self._items = list(items) 
      random.shuffle(self._items) 
   def pick(self): 
      try:
         return self._items.pop()
      except IndexError:
         raise LookupError(‘pick from empty BingoCage‘) 
   def __call__(self): 
      return self.pick()

>>> bingo = BingoCage(range(3))
>>> bingo.pick()
1 >>> bingo()
0 >>> callable(bingo)
True

7.函數內省

列出常規對象沒有而函數有的屬性:



用戶定義的函數的屬性:





8.從定位參數到僅限關鍵字參數



tag函數的調用:




cls只能作為關鍵字參數傳入

僅限關鍵字參數是python3新增的特性。
定義函數若想指定僅限關鍵字參數,要把它們放到前面有*的參數後面
如果不想支持數量不定的定位參數,想支持僅限關鍵字參數,那麽在簽名中放一個*

9.獲取關於參數的信息

假設定義了如下函數:

>>> def clip(text, max_len=80):
"""get text"""
end = None
if len(text) > max_len:
space_before = text.rfind(‘‘, 0, max_len)
if spece_before >= 0:
end = space_before
else:
space_after = text.rfind(‘‘, max_len)
if space_after >= 0:
end = space_after
if end is None:
end = len(text)
return text[:end].rstrip()

提取關於函數參數的信息:

>>> clip.__defaults__
(80,)
>>> clip.__code__
<code object clip at 000000000110FCB0, file "<pyshell#80>", line 2>
>>> clip.__code__.co_varnames
(‘text‘, ‘max_len‘, ‘end‘, ‘space_before‘, ‘space_after‘)
>>> clip.__code__.co_argcount
2

在python 3 中,使用inspect模塊:


10.函數註解

python3 提供了一種句法,用於為函數聲明中的參數和返回值附加元數據

函數聲明中的各個參數可以在:之後增加註解表達式
如果參數有默認值,註解放在參數名和=號之間。
如果想註解返回值,在)和函數聲明末尾的:之間添加 ->和一個表達式,表達式可以是任何類型,註解中最常用的類型是類(str,int)和字符串(‘int > 0‘)

註解不會做任何處理,只是存儲在函數的__annotations__屬性中

可以用inspect,signature()提取註釋

11.支持函數式編程的包

11.1 operator模塊

operator.mul


operator.itemgetter
根據元組的某個字段給元組列表排序

如果把多個參數傳遞給itemgetter,它構建的函數會返回提取的值構成的元組:

itemgetter不僅支持序列,還支持映射和任何實現__getitem__方法的類

operator.attrgetter
它創建的函數根據名稱提取對象的屬性。如果把多個屬性傳給attrgetter,它會返回提取的值構成的元組。如果參數中包含.,它會深入嵌套對象,獲取指定的屬性


operator.methodcaller
它創建的函數會在對象上調用參數指定的方法


11.2 使用functools.partial凍結參數

functools.partial這個高階函數用於部分應用一個函數。部分應用是指,基於一個函數創建一個新的可調用對象,把原函數的某些參數固定。使用這個函數可以把接受一個或多個參數的函數改編成需要回調的API,這樣參數更少

閱讀筆記4:一等函數