python 一等函数

一等函数

首先要明确一等对象的概念,一等对象是一个编程语言里的概念,满足以下条件:

  1. 在运行时创建
  2. 能赋值给变量或者是数据结构中的元素
  3. 能作为参数传给函数
  4. 能作为函数的返回结果

在python中,常常把“函数视作一等对象”称为“一等函数”。

下例是把函数视为对象的一个例子:

def foo(n):
    return n
tmp = foo
tmp(1)

高阶函数

接受函数为参数或者把函数作为返回结果的就是高阶函数。sorted是一个例子:

def reverse(word):
    return word[::-1]
sorted(tmp, key=reverse)

上例的意思是按照reverse后的字典序给tmp这个列表排序。

在python3中比较常见的高阶函数还有map, filter, reduce,但是在python3中一般存在更好的方式替换这三种函数。

# map
list(map(foo, range(6)))
[foo(n) for n in range(6)]
# filter
list(map(foo, filter(lambda n: n % 2, range(6))))
[foo(n) for n in range(6) if n % 2]

可见,map和filter的直接替代品是生成器表达式。而reduce在python3中不再是内置函数,而是被放到了functools中:

reduce的通用思想是:把某个操作作用到序列的元素上,把一系列的值聚合成一个值。reduce菜鸟教程

类似的内置函数有sum,any,all

  1. sum 求一个序列的值的和
  2. any(iterable) 只要iterable中有一个True,返回True
  3. all(iterable) iterable中的值都是True时,返回True

匿名函数

lambda关键字在python表达式中创建匿名函数。lambda中的定义体不能赋值,也不能使用try,while等语句

python中除非要作为参数传给高阶函数,否则尽可能不使用lambda函数。

可调用对象

除了用户定义的函数,可调用运算符也可以应用到其他对象上。可以使用callable判断是否可以调用。

  1. 用户定义的函数:使用def或者lambda创建
  2. 内置函数:使用C语言实现的函数
  3. 内置方法:dict.get
  4. 方法:在类的定义体中定义的函数
  5. 类:调用一个类时__new__->init
  6. 类的实例:如果类定义了__call__方法,那么它的实例也可以被调用。

接下来说明如何把类的实例变成可调用的对象

用户定义的可调用类型

任何实现了__call__的python对象都可以被调用。

函数内省

dir()

列出常规对象没有而函数有的属性,计算两个属性集合的差集即可

从定位参数到仅限关键字参数

调用函数时使用*和**展开可迭代对象,映射到单个参数。

def tag(name, *content, cls=None, **attrs):
    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)

简单理解就是,有名的参数被attr捕获,没有名字的参数被content捕获。

获取参数相关的信息

获取函数的签名,可以使用inspect模块:

from inspect import signature
sig = signature(foo)

其中,__defaults__元组保存定位参数和关键字参数的默认值。code.co_varnames保存参数名称。这样获取参数信息的问题在于这两个元组中的顺序不定,所以使用signature,生成一个有序映射,把参数名称和参数默认值一一对应起来。

而且signature中有一个bind方法,可以在参数传入函数之前进行格式的检查,如果确实必要的参数,会抛出TypeError,提示缺少参数。

函数注解

先来看一个有注解的函数:

def clip(text: str, max_len: 'int > 0' = 80) -> str:
    ......

参数的注解放在默认值前,冒号之后,返回值的注解在右括号后加一个箭头和返回值类型。注解不会进行任何处理,只会存在__annotations__中。

注意!!不会进行任何处理的意思是python只会把它当做一堆字串保存起来,仅作为参考的metadata使用,不会做类型检查,不做强制验证,不做类型验证。目前,只有signature函数知道如何提取注解。

sig.parameters

parameters是一个字典,建立参数名与参数注解的映射关系。

如果忘记了,直接看dir即可。

实际上,functools是一个非常有用的包,我们会在之后对其进行更深入的学习~

posted @ 2021-07-24 14:11  xinze  阅读(117)  评论(0编辑  收藏  举报