Python3 中作为一等对象的函数解析
Python3函数
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()。但你也可以自己创建函数,这被叫做用户自定义函数。
在Python语言中,函数与整数、字符串、字典等基本数据类型一样,都是 一等对象。所谓一等对象,即满足如下三个条件:
- 在运行时创建
- 能赋值给变量
- 能作为函数的参数或返回值
以下IDLE中的代码即在运行时创建了函数 factorial:
>>>deffactorial(n): ...'''calculatesn!''' ...return1ifn<2elsen*factorial(n-1) ... >>>factorial(5) 120 >>>factorial.__doc__ 'calculatesn!' >>>type(factorial)>>>fact=factorial >>>fact >>>fact(5) 120 >>>list(map(fact,range(10))) [1,1,2,6,24,120,720,5040,40320,362880]
从输出中可以看出, factorial是 function类的实例对象, __doc__是 factorial对象众多属性中的一个。
可以把 factorial函数赋值给变量 fact,通过 fact变量调用 factorial函数。还可以把 factorial作为参数传递给 map函数。
这些行为表现了函数作为一等对象的特性。
一、高阶函数
接受函数作为参数,或者把函数作为返回值的函数即为 高阶函数。
如内置用于排序的 sorted函数,它的 key参数用于传入一个函数,在需要排序的每个元素上执行特定的操作。如根据单词长度对多个字符串进行排序:
>>>fruits=['strawberry','fig','apple','cherry','raspberry','banana'] >>>sorted(fruits,key=len) ['fig','apple','cherry','banana','raspberry','strawberry']
任何单参数的函数都可以作为 key的值传给 sorted函数,如把单词反向拼写作为排序条件:
>>>defreverse(word): ...returnword[::-1] ... >>>reverse('test') 'tset' >>>sorted(fruits,key=reverse) ['banana','apple','fig','raspberry','strawberry','cherry']
map、filter与reduce
函数式编程语言通常会提供 map、 filter和 reduce三个高阶函数或者实现了类似功能的函数。Python3中的列表推导和生成器即具有 map和 filter函数的功能。
参考如下示例:
>>>deffact(n): ...return1ifn<2elsen*fact(n-1) ... >>>list(map(fact,range(6))) [1,1,2,6,24,120] >>>[fact(n)forninrange(6)] [1,1,2,6,24,120] >>>list(map(fact,filter(lambdan:n%2,range(6)))) [1,6,120] >>>[fact(n)forninrange(6)ifn%2] [1,6,120]
通过列表推导可以完成与 map或 filter函数类似的工作,且可读性更高,也避免了使用 lambda表达式。
reduce在Python2中是内置函数,但在Python3中被移到了 functools模块中。 reduce可以把某个操作连续地应用到某个序列上,累计所有的结果,把产生的一系列值规约成一个值。因此常用于求和计算,但内置的 sum函数在可读性和性能方面更优。
>>>fromfunctoolsimportreduce >>>fromoperatorimportadd >>>reduce(add,range(101)) 5050 >>>sum(range(101)) 5050
二、匿名函数
可以使用 lambda关键字在Python表达式内创建匿名函数。
在函数的参数列表中最适合使用匿名函数。如前面的根据字符串反序后的结果对单词列表进行排序,可以使用 lambda匿名函数替代传入 sorted的 reverse函数:
>>>fruits=['strawberry','fig','apple','cherry','raspberry','banana'] >>>sorted(fruits,key=lambdaword:word[::-1]) ['banana','apple','fig','raspberry','strawberry','cherry']
lambda表达式 lambdawords:words[::-1]即等同于之前的 reverse函数:
defreverse(word): returnword[::-1]
除了作为参数传给某个高阶函数外,Python很少使用匿名函数。
三、可调用对象
除了用户自定义的函数,其他可调用对象也可以使用调用运算符(即 ())。
Python的数据模型中共包含7种可调用对象:
- 用户自定义函数:使用 def语句或 lambda表达式创建的函数
- 内置函数:由C语言(CPython)实现的函数,如 len或 time.strftime等
- 内置方法:使用C语言实现的方法,如 dict.get
- 方法:在类的定义体中定义的函数
- 类:类在调用时会使用 __new__方法创建实例,然后运行 __init__初始化实例,最后将实例返回给调用方。调用类相当于调用函数。
- 类的实例:如果类的定义中实现了 __call__方法,则其实例可以作为函数调用
- 生成器:使用yield关键字的函数或方法。可以返回生成器对象。
使用内置的 callable()函数可以确认对象是否可调用。
任何Python对象都可以表现得像函数,只需实现该实例的 __call__方法。
如下面的 bingocall.py,从列表中随机取出一个元素:
importrandom classBingoCage: def__init__(self,items): self._items=list(items) random.shuffle(self._items) defpick(self): try: returnself._items.pop() exceptIndexError: raiseLookupError('pickfromemptyBingoCage') def__call__(self): returnself.pick() bingo=BingoCage(range(50)) print(bingo.pick()) #=>38 print(bingo()) #=>22 print(callable(bingo)) #=>True
bingo是 BingoCage类的一个实例,由于 BingoCage类中实现了 __call__方法,则 bingo对象是可调用的( bingo())。
四、支持函数式编程的模块
operator
在函数式编程中,经常需要将算术运算符当作函数使用。如不使用递归计算阶乘。
使用 reduce和 lambda表达式计算阶乘:
>>>fromfunctoolsimportreduce >>>deffact(n): ...returnreduce(lambdaa,b:a*b,range(1,n+1)) ... >>>fact(5) 120
Python中的 operator为多个运算符提供了对应的函数,可以避免写 lambdaa,b:a*b这种匿名函数。
使用 reduce和 operator.mul计算阶乘:
>>>fromoperatorimportmul >>>fromfunctoolsimportreduce >>>deffact(n): ...returnreduce(mul,range(1,n+1)) ... >>>fact(5) 120
operator模块中还有一类 itemgetter和 attrgetter函数,可以替代从序列中取出元素或读取属性的 lambda表达式。
如根据元组中的第二个元素对多个元组进行排序:
>>>metro_data=[ ...('Tokyo','JP',36.933,(35.689722,139.691667)), ...('DelhiNCR','IN',21.935,(28.613889,77.208889)), ...('MexicoCity','MX',20.142,(19.433333,-99.133333)), ...('NewYork-Newark','US',20.104,(40.808611,-74.020386)), ...('SaoPaulo','BR',19.649,(-23.547778,-46.635833)), ...] >>>fromoperatorimportitemgetter >>>forcityinsorted(metro_data,key=itemgetter(1)): ...print(city) ... ('SaoPaulo','BR',19.649,(-23.547778,-46.635833)) ('DelhiNCR','IN',21.935,(28.613889,77.208889)) ('Tokyo','JP',36.933,(35.689722,139.691667)) ('MexicoCity','MX',20.142,(19.433333,-99.133333)) ('NewYork-Newark','US',20.104,(40.808611,-74.020386))
如果把多个参数传递给 itemgetter,则该函数会返回由提取的值构成的元组:
>>>cc_name=itemgetter(1,0) >>>forcityinmetro_data: ...print(cc_name(city)) ... ('JP','Tokyo') ('IN','DelhiNCR') ('MX','MexicoCity') ('US','NewYork-Newark') ('BR','SaoPaulo')
attrgetter与 itemgetter作用类似,可以根据名称提取对象的属性。
operator模块中还有一个 methodcaller函数,可以用来在某个对象上调用由参数指定的方法。
>>>fromoperatorimportmethodcaller >>>s='Thetimehascome' >>>upcase=methodcaller('upper') >>>upcase(s) 'THETIMEHASCOME' >>>hiphenate=methodcaller('replace','','-') >>>hiphenate(s) 'The-time-has-come' functools.partial
高阶函数 functools.partial用来 部分应用某个函数。即基于某个函数创建一个新的可调用对象,并把原函数的某些参数固定。
如使用 partial把一个接受双参数的函数改编成单参数的可调用对象:
>>>fromoperatorimportmul >>>fromfunctoolsimportpartial >>>triple=partial(mul,3) >>>triple(7) 21 >>>list(map(triple,range(1,10))) [3,6,9,12,15,18,21,24,27]
partial()函数返回一个 functools.partial对象,该对象提供对原函数的访问和固定原函数参数的行为。
>>>defgreeting(words,name): ...returnf'{words},{name}!' ... >>>fromfunctoolsimportpartial >>>greeting2=partial(greeting,name='skitar') >>>greeting2("what'sup") "what'sup,skitar!" >>>greeting2 functools.partial(,name='skitar')
总结
以上所述是小编给大家介绍的Python3中作为一等对象的函数解析,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。