python自定义高阶函数_Python对象函数,高阶函数,可调用对象,自定义可调用类型,函数内省,型函数...

文 | 菊子皮(转载请注明出处)

关注公众号:

AIAS编程有道

环境:Python 3.7,VS Code

读书总结 :流畅的Python

可以看成对象的函数

Python中的函数可以看成一个对象。以下例为例有,先定义一个简单的函数,并调用和查看相关信息。

def factorial(n): # <1>

'''return n!'''

return 1 if n < 2 else n * factorial(n - 1)

print(factorial(10)) # 3628800

print(factorial.__doc__) # return n! <2>

print(type(factorial)) # <3>

说明:

<1> 创建一个计算递归的函数,并在下一行使用固定格式进行函数注释

<2>

__doc__

是函数对象众多属性中的一个

<3> factorial是function类的

实例

,这时就有对象的感觉了

补充:

__doc__

属性用于生成对象的帮助文本。可通过help(factorial)命令输出的内容。

再做进一步分析,把factorial函数赋值给变量fact,然后通过变量名调用。还能把它作为参数传给map函数。map函数返回一个可迭代对象,里面的元素是把第一个参数(一个函数)应用到第二个参数(一个可迭代对象,这里是range(11))中各个元素上得到的结果,之前也有过内建函数的介绍。

fact = factorial

print(fact) #

print(fact(8)) # 40320

print(map(factorial, range(11))) #

print(list(map(fact, range(11)))) # [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]

高阶函数

接受函数为参数,或者把函数作为结果返回的函数是高阶函数(higher-orderfunction),这也是函数式编程的特点之一。例如map函数,sorted函数(key参数用于提供一个函数)。

在函数式编程范式中,最为人熟知的高阶函数有map、filter、reduce。如果想使用不定量的参数调用函数,可以编写fn(*args, **keywords)。

可调用对象

除了用户定义的函数,调用运算符(即( ))还可以应用到其他对象上。如果想判断对象能否调用,可以使用内置的callable( )函数。Python数据模型文档列出了7种可调用对象。

用户定义的函数: 使用def语句或lambda表达式创建。

内置函数:使用C语言(CPython)实现的函数,如len或time.strftime。

内置方法:使用C语言实现的方法,如dict.get。

方法:在类的定义体中定义的函数。

类:调用类时会运行类的

__new__

方法创建一个实例,然后运行

__init__

方法,初始化实例,最后把实例返回给调用方。因为Python没有new运算符,所以调用类相当于调用函数。

类的实例:如果类定义了

__call__

方法,那么它的实例可以作为函数调用。

生成器函数:使用yield关键字的函数或方法。调用生成器函数返回的是生成器对象。

Python中有各种各样可调用的类型,因此判断对象能否调用,最安全的方法是使用内置的callable( )函数,如下:

print(abs, str, 13, sep="\t")

# 查看对象是否可以被调用

print([callable(obj) for obj in (abs, str, 13)])

# 13

# [True, True, False]

用户定义的可调用类型

不仅Python函数是真正的对象,任何Python对象都可以表现得像函数,只需实现实例方法

__call__

。如下示例:

描述:实现BingoCage类,这个类的实例使用任何可迭代对象构建,而且会在内部存储一个随机顺序排列的列表。调用实例会取出一个元素。

import random

class BingoCage:

def __init__(self, items):

self._items = list(items) # <1>

random.shuffle(self._items) # <2>

def pick(self): # <3>

try:

return self._items.pop()

except IndexError:

raise LookupError('pick from empty BingoCage') # <4>

def __call__(self): # <5>

return self.pick()

说明:

<1>

__init__

接受任何可迭代对象;在本地构建一个副本,防止列表参数的意外副作用。

<2> shuffle定能完成工作,因为self._items是列表,打乱self._items。

<3> 主要作用的方法。

<4> 如果self._items为空,抛出异常,并设定错误消息。

<5>

bingo.pick( )的快捷方式是bingo( )

该类的使用方法如下,注意,bingo实例可以作为函数调用,而且内置的callable(…)函数判定它是可调用的对象。

bingo = BingoCage(range(3))

print(bingo.pick()) # 1

print(bingo()) # 2

print(callable(bingo)) # True

实现

__call__

方法的类是创建函数类对象的简便方式,此时必须在内部维护一个状态,让它在调用之间可用,例如BingoCage中的剩余元素。装饰器就是这样。装饰器必须是函数,而且有时要在多次调用之间“记住”某些事[例如备忘(memoization),即缓存消耗大的计算结果,供后面使用]。

函数内省

除了

__doc__

,函数对象还有很多属性。使用dir函数可以探知factorial(

dir(factorial)

)具有下述属性:

['__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__']

其中大多数属性是Python对象共有的。

先了解一下

__dic__

。与用户定义的常规类一样,函数使用

__dict__

属性存储赋予它的用户属性。这相当于一种基本形式的

注解

(一种编程方式)。一般来说,为函数随意赋予属性不是很常见的做法。

下面重点说明函数专有而用户定义的一般对象没有的属性。计算两个属性集合的差集便能得到函数专有属性列表。如下:

class C:

pass # <1>

obj = C() # <2>

def func():

pass # <3>

print(set(dir(func)) - set(dir(obj))) # <4>

# {'__kwdefaults__', '__get__', '__closure__', '__qualname__', '__code__', '__annotations__', '__call__', '__name__', '__defaults__', '__globals__'}

说明:

<1> 创建一个空的用户定义的类

<2> 创建一个实例。

<3> 创建一个空函数。

<4> 计算差集,然后排序,得到类的实例没有而函数有的属性列表。

这些函数说明可如下表。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值