第5章–一等函数
一等对象定义为满足以下条件的程序实体
- 在运行时创建
- 能赋值给变量或者数据结构中的元素
- 能作为参数传给函数
- 能作为函数的返回结果
python中函数就是一等对象,简称一等函数
5.1 把函数视为对象
函数是一个对象,自定义的函数是函数对象的一个实例,函数对象有一些默认的属性,比如__doc__
def factorial(n):
'''return n!'''
return 1 if n<2 else n*factorial(n-1)
print(factorial(5)) # 120
print(factorial.__doc__) # return n!
print(type(factorial)) #<class 'function'>
5.2 高阶函数
接受函数为参数,或者把函数作为结果返回的函数是高阶函数(higher-order function)。
map、sorted、filter就是高阶函数
map、filter可以用列表推导式替代
5.3 匿名函数
lambda,只能写一些简单函数,适合用在参数传入一个函数对象时
5.4 可调用对象
python有七种可调用对象
- 用户自定义函数,def语句或lambda定义的函数
- 内置函数 使用 C 语言(CPython)实现的函数,如 len 或 time.strftime
- 内置方法 使用 C 语言实现的方法,如 dict.get。
上面二者的差异是方法是某个类里面的函数,函数则是不在类里面的 - 方法
- 类,生成类的实例时其实就是call 类的一个过程
- 类的实例,如果类定义了__call__方法,那么它的实例可以作为函数调用
- 生成器函数,使用yield返回的函数或方法
https://stackoverflow.com/questions/111234/what-is-a-callable 这里的回答在cpython代码的侧面来解释callable函数的判断,callable(x)如果要返回True,要满足下面两个条件之一
- x是类的实例,并且类实现了__call__方法
- x->ob_type->tp_call != NULL
5.5 用户定义的可调用类型
自定义类实现__call__方法就行,略
5.6 函数内省
函数有很多内置的属性,列举如下
[’__annotations__’, ‘__call__’,
‘__class__’, ‘__closure__’, ‘__code__’, ‘__defaults__’,
‘__delattr__’, ‘__dict__’, ‘__dir__’, ‘__doc__’, ‘__eq__’,
‘__format__’, ‘__ge__’, ‘__get__’, ‘__getattribute__’,
‘__globals__’, ‘__gt__’, ‘__hash__’, ‘__init__’,
‘__init_subclass__’, ‘__kwdefaults__’, ‘__le__’, ‘__lt__’, ‘__module__’,
‘__name__’, ‘__ne__’, ‘__new__’, ‘__qualname__’, ‘__reduce__’,
‘__reduce_ex__’, ‘__repr__’,
‘__setattr__’, ‘__sizeof__’, ‘__str__’,
‘__subclasshook__’]
函数专有而自定义类没有的属性
5.7
函数参数中用* 可以让后面的参数必须以关键字的形式传入,用*而不是a=1这样的形式是可以用不用默认值的关键字参数
def f(*,a,b):
return a,b
print(f(a=1,b=2))# 1,2
print(f(1,b=2))
# TypeError: f() takes 0 positional arguments but 1 positional argument (and 1 keyword-only argument) were given
5.8 获取关于参数的信息
可以用inspect.signature函数获取函数参数的信息
from inspect import signature
def f(a,b=1):
return a,b
sig=signature(f)
print(sig) #(a, b=1)
for name,param in sig.parameters.items():
print(param.kind," : ",name,param.default)
# POSITIONAL_OR_KEYWORD : a <class 'inspect._empty'>
# POSITIONAL_OR_KEYWORD : b 1
kind属性的值是_ParameterKind 类中的 5 个值之一
- POSITIONAL_OR_KEYWORD可以通过定位参数和关键字参数传入的形参(多数 Python 函数的参数属于此类)。
- VAR_POSITIONAL 定位参数元组。
- VAR_KEYWORD 关键字参数字典。
- KEYWORD_ONLY 仅限关键字参数(Python 3 新增)。
- POSITIONAL_ONLY 仅限定位参数;目前,Python 声明函数的句法不支持,但是有些使用 C 语言实现且不接受关键字参数的函数(如 divmod)支持。
signature.bind()方法可以把实参绑定到形参上,可以用于调用函数前对函数调用的参数正确性的判断
from inspect import signature
def f(a,b):
return a,b
input_params={'a':1,'b':2}
sig=signature(f)
sig.bind(**input_params)
del input_params['a']
sig.bind(**input_params) # TypeError: missing a required argument: 'a'
5.9 函数注解
from inspect import signature
def f(a:int,b:'int>0'=1)->(int,int):
return a,b
sig=signature(f)
print(sig) #(a:int, b:'int>0'=1) -> (<class 'int'>, <class 'int'>)
for name,param in sig.parameters.items():
print(param.kind," : ",name,param.default)
# POSITIONAL_OR_KEYWORD : a <class 'inspect._empty'>
# POSITIONAL_OR_KEYWORD : b 1
python对函数注解的唯一操作是把他们放到函数的__annotations__属性里,不会做任何的验证和检查,函数注解方便了ide的静态类型检查
5.10 支持函数式编程的包
-
operator模块,在函数式编程中,经常要把算术运算符当函数用,operator模块提供了算术运算符对应的函数,还提供了替代从序列中获取元素或者读取对象属性的函数itemgetter和attrgetter
-
functools.partial 可以用来固定参数,
from operator import mul
from functools import partial
triple=partial(mul,3)
print(triple(7)) #21