Fork me on GitHub

《流畅的Python》----第五章 一等函数

[toc]

第五章 一等函数

函数是一等对象,一等对象需满足

  • 在运行时创建
  • 能赋值给对象或者数据结构中的元素
  • 能作为参数传递给函数
  • 能作为函数的返回结果

在Python中,整数、字符串、字典等都是一等对象,函数也是一等对象,只是把函数视作一等对象的时候,简称为一等函数。

把函数视作对象

函数也是对象,本身是function类的实例

高阶函数

接受函数作为参数,或者把函数作为返回结果的函数叫做高阶函数。常见的高阶函数有map,filter,sorted等,其中mapfilter返回的是生成器。

allany的用法:

  • all(iterable),如果iterable的每个元素都是真值则返回True,all([])返回True
  • any(iterable),只要iterable有元素为真则返回true,all([])返回False

可调用对象

能使用()的都被叫做可调用对象,可使用callable()判断一个对象是否是可调用对象,python中有7中可调用对象:

  1. 用户定义的函数
  2. 内置函数
  3. 内置方法
  4. 方法
  5. 类,调用时会运行__new__方法创建一个实例,然后运行__init__方法初始化实例,最后把实例返回给调用方。
  6. 类的实例,前提是类定义了__call__方法。
  7. 生成器函数,在函数中使用了yieled语句的

用户定义的可调用类型

只需实现__call__方法。

例子,从打乱的列表中取出一个元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import random

calss 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 BingCage')

def __call__(self):
return self.pick()

1
2
3
4
5
6
>>> bingo = BingoCage(range(6))
>>> bingo.pick()
5
>>> bingo()
4
# bingo.pick()和bingo()的作用是一样的

函数内省

Wikipedia内省)的定义:
内省是指计算机程序在运行时(Run time)检查对象(Object)类型的一种能力,通常也可以称作运行时类型检查。

通俗来讲就是Python在运行时能够知道这个对象是什么,它能做什么,它包含哪些内容。

一些内省函数

  • dir(object):它返回一个列表,这个列表中包含object的所有属性
  • type:返回一个对象的类型
  • id:返回一个对象的id

获取关于参数的信息

函数对象有个__defaults__属性,它的值是一个元组,里面保存着定位参数和关键字参数的默认值。__kwdefaults__包含仅限关键字参数的默认值。参数的名称在__code__属性中,它的值是一个code对象引用。

函数注解

函数声明中的各个参数可以在:之后增加注解表达式。如果参数有默认值放在参数名和=之间。如果想添加返回值注解,在)和函数声明末尾:之间添加->和一个表达式。
注解存储在__annotations__属性中

支持函数式编程的包

operator

itmegetterattrgetter会自行构建函数,所起的作用类似于使用lambda表达式从序列中取出元素或者读取对象的属性。

itemgetter
下例利用itemgetter排序一个数组,itemgetter()的作用与lambda fields: fields[1]相同,创建一个接收集合的函数,返回索引位1的元素。

1
2
3
4
5
6
7
8
>>> metro_data = [('Tokyo', 'JP', 36.933, (35.689722, 139.691667)),('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)),('Sao Paulo', 'BR', 19.649, (-23.547778, -46.635833)),]

>>> for city in sorted(metro_data, key=itemgetter(1)):
... print(city)
...
('Sao Paulo', 'BR', 19.649, (-23.547778, -46.635833))
('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889))
('Tokyo', 'JP', 36.933, (35.689722, 139.691667))

attrgetter

它创建的函数根据名称提取对象的属性,如果把多个属性名传给attrgetter,它也会返回提取的值构成的元组。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> from collections import namedtuple
>>> LatLong = namedtuple('LatLong', 'lat long')
>>> Metropolis = namedtuple('Metropolis', 'name cc pop coord')
>>> metro_areas = [Metropolis(name, cc, pop, LatLong(lat, long)) for name,cc,pop,(lat,long) in metro_data]
>>> metro_areas[0]
Metropolis(name='Tokyo', cc='JP', pop=36.933, coord=LatLong(lat=35.689722, long=139.691667))
>>> metro_areas[0].coord.lat
35.689722
>>> from operator import attrgetter
>>> name_lat = attrgetter('name','coord.lat')
>>> for city in sorted(metro_areas,key=attrgetter('coord.lat')):
... print(name_lat(city))
...
('Sao Paulo', -23.547778)
('Delhi NCR', 28.613889)
('Tokyo', 35.689722)

methodcaller

methodcaller创建的函数会在对象上调用参数指定的方法。

例子

1
2
3
4
5
6
>>> from operator import methodcaller
>>> s = 'good good study, day day up'
>>> upcase = methodcaller('upper')
>>> upcase(s)
'GOOD GOOD STUDY, DAY DAY UP'
>>>

使用functools.partial冻结参数

functools.partial这个高阶函数用于部分应用一个函数。部分应用指的是,基于一个函数创建一个新的可调用对象,把原函数的某些参数固定。

例子

1
2
3
4
5
>>> from operator import mul
>>> from functools import partial
>>> triple = partial(mul,3)
>>> [triple(i) for i in range(6)]
[0, 3, 6, 9, 12, 15]