python函数的高级话题

本文详细讨论Python中的高级函数概念,包括递归与循环的比较、函数对象的属性和注解、lambda匿名函数及其应用场景。递归在处理复杂结构时有优势,函数的属性和注解提供了更多元化的功能,如内省和状态存储。lambda表达式则为短小的函数定义提供了便利。此外,还介绍了map、filter和reduce等函数式编程工具。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1 递归函数VS循环

2 函数对象:属性和注解

1)间接函数调用总结

2) 函数内省

3) 函数属性

4) 函数注解(python3)

3 lambda匿名函数

1) 序列映射函数map

2) filter和reduce


递归函数、函数属性和注释、lambda表达式,如map和filter这样的函数式编程工具都是本文叙述的内容。

谈到设计函数,必须要提到函数的耦合性和聚合性。关于如何避免耦合性,需要记住以下几点:1)对于输入使用参数,并且输出使用return语句,2)只有在真正必要的情况下使用全局变量,3)不要改变可变类型的参数,除非调用者希望这样做,4)避免直接改变在另一个模块文件中的变量。所谓聚合,要求每一个函数应该有一个单一的、统一的目标。python代码以简单明了著称,一个过长或者有着深层嵌套的函数往往就成为设计缺陷的征兆。

通常要使函数和其他编程组件中的外部依赖性最小化,函数的自包含性越好,它越容易被理解、复用和修改。

1 递归函数VS循环

递归是一种有用的技术,因为它允许程序遍历拥有任意的,不可预知的形状的结构。

下面是用递归的方式求和,过于技巧,直接使用循环即可,循环不需要在调用堆栈时针对每次迭代都有一个本地作用域的副本,还可以避免与函数调用相关的速度成本。

>>> def mysum(L):
...     if not L:
...             return 0
...     else:
...             return L[0] + mysum(L[1:])
...
>>> mysum([1,2,3,4,5])
15
# 循环
>>> L = [1,2,3,4,5]
>>> sum = 0
>>> while L:
...     sum += L[0]
...     L = L[1:]
...
>>> sum
15

递归的优势:处理任意结构

>>> def sumtree(L):
...     tot = 0
...     for x in L:
...             if not isinstance(x,list):
...                     tot += x
...             else:
...                     tot += sumtree(x)
...     return tot
...
>>> L = [1,[2,[3,4],5],6,[7,8]]
>>> print(sumtree(L))
36

2 函数对象:属性和注解

函数可以跨程序自由地传递和间接调用,也支持与调用根本无关的操作——属性存储和注解

1)间接函数调用总结

函数对象可以赋值给其他的名字,传递给其他函数,嵌入到数据结构,从一个函数返回给另一个函数等等

# 函数名直接是一个函数对象的引用
>>> def echo(message):
...     print(message)
...
>>> x = echo
>>> x('Indirect call!')
Indirect call!
# 传递给其他函数
>>> def indirect(func,arg):
...     func(arg)
...
>>> indirect(echo,'Argument call!')
Argument call!
# 嵌入到数据结构
>>> schedule = [(echo,'Spam!'),(echo,'Ham!')]
>>> for (func,arg) in schedule:
...     func(arg)
...
Spam!
Ham!

2) 函数内省

允许我们探索函数的本地变量和参数方面的细节,利用这些信息来管理函数

>>> def f(a):
...     b = 'spam'
...     return b*a
...
>>> f(8)
'spamspamspamspamspamspamspamspam'
>>> f.__name__
'f'
>>> dir(f)
['__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__']

3) 函数属性

除了系统定义的属性,我们可以向函数附加用户定义的任意属性。这些属性可以将状态信息附加给函数对象,而不必使用全局、非本地和类等其他技术。这些属性可以在函数自生的任何地方访问,类似其他语言的“静态本地变量”的访问方式。属性与对象相关,不与作用域相关,但最终的效果是相似的。

>>> f.count = 0
>>> f.count += 1
>>> f.count
1
>>> f.handles = 'Button-Press'
>>> f.handles
'Button-Press'
>>> dir(f)
['__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__', 'count', 'handles']
>>>

4) 函数注解(python3)

注解信息是与函数参数和结果相关的任意的用户定义的数据。它有特殊的语法,不做任何事情,是可选的。出现的时候,只是直接附加到函数对象的__annotations__属性供其他用户使用。

注解编写在def的头部,对于参数,它们出现在紧随参数名之后的冒号之后;对于返回值,它们编写于紧跟在参数列表之后的一个->之后。当注解出现的时候,python将它们收集到字典中,并将它们附加给函数对象,参数名变成键,若返回值也编写注解,则存在在键“return”下

>>> def func(a:'spam', b:(1,10), c:float)->int:
...     return a+b+c
...
>>> func(1,2,3)
6
>>> func.__annotations__
{'a': 'spam', 'b': (1, 10), 'c': <class 'float'>, 'return': <class 'int'>}

注意:即使编写了注解,也可以对参数使用默认值,注解出现在默认值之前。

3 lambda匿名函数

python提供了一种生成函数对象的表达式形式,由于它于LISP语言中的一个工具很相似,所以称为lambda。就像def一样,这个表达式创建一个之后能够调用的函数,但是它返回了一个函数而不是将这个函数赋值给一个变量名。这也是lambda有时叫做匿名函数的原因。

lambda的一般形式是关键字lambda,之后是一个或多个参数,后面紧跟的是一个冒号,之后是一个表达式

lambda与普通函数的区别是lambda是一个表达式,而不是一个语句;lambda的主体是一个单个表达式,而不是一个代码块。默认参数也可以在lambda参数中使用。lambda的主体代码像在def内的代码一样都遵循相同的作用域查找法则。

>>> f = lambda x,y,z: x+y+z
>>> f(2,3,4)
9
>>> x = lambda a='fee', b='fie', c='foe': a+b+c
>>> x('wee')
'weefiefoe'

>>> def knights():
...     title = 'Sir'
...     action = (lambda x: title + ' ' + x)
...     return action
...
>>> act = knights()
>>> act('robin')
'Sir robin'

使用lambda的原因:起到函数速写的作用,可以利用列表、字典或者其他数据结构来构建行为表

>>> L = [lambda x:x**2, lambda x: x**3, lambda x: x**4]
>>> print(L[0](3))
9
>>> key  = 'got'
>>> {'already':(lambda: 2+2),
... 'got': (lambda: 2*4),
... 'one':(lambda: 2**6)}[key]()
8

当python创建这个字典的时候,每个嵌套的lambda都会生成并留下一个在之后能够调用的函数,通过键索引来取回其中一个函数,而括号使取出的函数被调用。

1) 序列映射函数map

程序中常常要做的是对每一个元素进行一个操作并将结果集合起来,map能完成此功能,它会对一个序列对象中的每一个元素应用被传入的函数,并且返回一个包含所有函数调用的一个对象

>>> def inc(x): return x + 10
...
>>> counters = [1,2,3,4]
>>> list(map(inc, counters))
[11, 12, 13, 14]

2) filter和reduce

filter:基于某个函数过滤一些函数

reduce:对每对元素都应用函数并运行到最后结果。reduce传递了当前的和或乘积以及列表中的下一个元素。

>>> list(filter((lambda x: x > 0), range(-5, 5)))
[1, 2, 3, 4]
>>> from functools import reduce
>>> reduce((lambda x, y: x + y),[1,2,3,4])
10

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

vinkuan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值