首页 > 编程知识 正文

python函数定义(python def函数)

时间:2023-05-06 04:05:25 阅读:87963 作者:733

一、lambda匿名函数详解

lambda函数是快速定义单行的最小函数,是从Lisp借用的,可以在需要函数的地方使用。

1 .以下示例比较了传统的函数定义def和lambda的定义方法。

德夫(x,y ) :

.返回x * y

.

f (2,3 ) ) )。

6

g=lambda x,y: x * y

g (2,3 ) )。

根据6所述,两个函数得到相同的结果,但对于实现简单功能的函数,可以使用lambda函数进行更紧凑、更灵活的定义。 也可以将函数直接分配给一个变量,然后用变量名称表示函数名称。 其实,lambda函数很多时候不需要代入变量。

lambda函数的使用有几个注意事项

lambda函数接受任意数量的参数,包括可选参数,并返回一个表达式的值。 lambda函数不能包含命令。 此外,不能包含多个表达式。 lambda语句用于创建函数对象。 基本上,lambda需要参数,后面只有一个表达式作为函数体,表达式的值由这个新创建的函数返回。 请注意,print语句也不能以lambda格式使用,只能使用表达式。 3. def和lambda的区别

lambda在python上使用lambda创建匿名函数,但使用def创建的方法有名称。 lambda会创建函数对象,但不会将此函数对象分配给标识符,而def会将函数对象分配给变量。 lambda是表达式,def是语句。 因为def是一个语句,所以并不是不能嵌套表达式。 lambda表达式只能在“:”之后有一个表达式。 也就是说,在def中,可以在return中返回的东西可以放在lambda后面,不能在return中返回的东西也不能在python lambda后面定义。 因此,像if、for和print这样的语句不能用于lambda。 lambda一般只用于定义简单的函数。 4 .示例

类人猿:

age=0

gender='male '。

def _ init _ (自、自、生) :

自我介绍=自我介绍

self . gender=gender

EF tostring (自助) :

返回代理: ' str (自助.代理)/t生成器: '自助.生成器

list=[人造(21,'人造) 20,'人造),人造) 34,'人造),

朋友(19,“失败”)

打印足球甲级联赛: '

列表:之外

使用打印p.tostring (

list.sort(lambdaP1,p 2:厘米) p2 . age,p2 . age ) )

打印'/Nafterascendingsort : '

列表:之外

使用打印p.tostring (

list.sort(lambdaP1,P2:-CMP ) p2 . age,p2 . age ) )

打印'/Nafterdescendingsort : '

列表:之外

print p . toString ()

二、递归函数

1.定义

在函数内部,可以调用其他函数。 如果某个函数在内部调用自己,则该函数是递归函数。

2 .递归特性

请记住,所有递归函数的结束条件在相邻的两次重复之间存在密切的联系。 上一次必须做下一次的准备。 上一次的输出通常是下一次的输入。 递归没有效率。 递归层次过多会导致堆栈溢出。 (在计算机中,函数调用是通过一种叫做堆栈的数据结构实现的,每次进入一个函数调用时,都会在堆栈中添加一个堆栈帧,每次函数返回时,堆栈都会减少一个堆栈帧。 因为栈的大小不是无限的,所以递归调用的次数过多会导致栈溢出()递归的层数在python中是有限的997/998层,可以使用sys模块来更改递归的层数(sys.ss8 ) 3 .实例详细情况

计算阶乘n!=1 x 2 x 3 x . x n

fact(n )可以表示为nxfact ) n-1 ),只有在n=1时才需要特别的处理。

deffact(n ) :

if n==1:

返回1

计算returnn*fact(5(n-1 ) fact )5)时,从函数的定义中可以看到如下的计算过程。

===fact(5)。

===5*脸部(4)

===5* (4*传真)3) )

===5*(4* )3*fact )2) )

===5*(4* )3* )2*面貌(1) )

==

==> 5 * (4 * (3 * (2 * 1))) ===> 5 * (4 * (3 * 2)) ===> 5 * (4 * 6) ===> 5 * 24 ===> 120

递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。

使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。可以试试fact(1000):

>>> fact(1000) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 4, in fact ... File "<stdin>", line 4, in fact RuntimeError: maximum recursion depth exceeded

解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。

尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。

上面的fact(n)函数由于return n * fact(n - 1)引入了乘法表达式,所以就不是尾递归了。要改成尾递归方式,需要多一点代码,主要是要把每一步的乘积传入到递归函数中:

def fact(n): return fact_iter(1, 1, n) def fact_iter(product, count, max): if count > max: return product return fact_iter(product * count, count + 1, max)

可以看到,return fact_iter(product * count, count + 1, max)仅返回递归函数本身,product * count和count + 1在函数调用前就会被计算,不影响函数调用。

fact(5)对应的fact_iter(1, 1, 5)的调用如下:

===> fact_iter(1, 1, 5) ===> fact_iter(1, 2, 5) ===> fact_iter(2, 3, 5) ===> fact_iter(6, 4, 5) ===> fact_iter(24, 5, 5) ===> fact_iter(120, 6, 5) ===> 120

尾递归调用时,如果做了优化,栈不会增长,因此,无论多少次调用也不会导致栈溢出。

遗憾的是,大多数编程语言没有针对尾递归做优化,Python解释器也没有做优化,所以,即使把上面的fact(n)函数改成尾递归方式,也会导致栈溢出。

有一个针对尾递归优化的decorator,可以参考源码:

http://code.activestate.com/recipes/474088-tail-call-optimization-decorator/

#!/usr/平常的芹菜/env python2.4 # This program shows off a python decorator( # which implements tail call optimization. It # does this by throwing an exception if it is # it's own grandparent, and catching such # exceptions to recall the stack. import sys class TailRecurseException: def __init__(self, args, kwargs): self.args = args self.kwargs = kwargs def tail_call_optimized(g): """ This function decorates a function with tail call optimization. It does this by throwing an exception if it is it's own grandparent, and catching such exceptions to fake the tail call optimization. This function fails if the decorated function recurses in a non-tail context. """ def func(*args, **kwargs): f = sys._getframe() if f.f_back and f.f_back.f_back and f.f_back.f_back.f_code == f.f_code: raise TailRecurseException(args, kwargs) else: while 1: try: return g(*args, **kwargs) except TailRecurseException, e: args = e.args kwargs = e.kwargs func.__doc__ = g.__doc__ return func @tail_call_optimized def factorial(n, acc=1): "calculate a factorial" if n == 0: return acc return factorial(n-1, n*acc) print factorial(10000) # prints a big, big number, # but doesn't hit the recursion limit. @tail_call_optimized def fib(i, current = 0, next = 1): if i == 0: return current else: return fib(i - 1, next, current + next) print fib(10000) # also prints a big number, # but doesn't hit the recursion limit.

现在,只需要使用这个@tail_call_optimized,就可以顺利计算出fact(1000):

>>> fact(1000) 402387260077093773543702433923003985719374864210714632543799910429938512398629020592044208486969404800479988610197196058631666872994808558901323829669944590997424504087073759918823627727188732519779505950995276120874975462497043601418278094646496291056393887437886487337119181045825783647849977012476632889835955735432513185323958463075557409114262417474349347553428646576611667797396668820291207379143853719588249808126867838374559731746136085379534524221586593201928090878297308431392844403281231558611036976801357304216168747609675871348312025478589320767169132448426236131412508780208000261683151027341827977704784635868170164365024153691398281264810213092761244896359928705114964975419909342221566832572080821333186116811553615836546984046708975602900950537616475847728421889679646244945160765353408198901385442487984959953319101723355556602139450399736280750137837615307127761926849034352625200015888535147331611702103968175921510907788019393178114194545257223865541461062892187960223838971476088506276862967146674697562911234082439208160153780889893964518263243671616762179168909779911903754031274622289988005195444414282012187361745992642956581746628302955570299024324153181617210465832036786906117260158783520751516284225540265170483304226143974286933061690897968482590125458327168226458066526769958652682272807075781391858178889652208164348344825993266043367660176999612831860788386150279465955131156552036093988180612138558600301435694527224206344631797460594682573103790084024432438465657245014402821885252470935190620929023136493273497565513958720559654228749774011413346962715422845862377387538230483865688976461927383814900140767310446640259899490222221765904339901886018566526485061799702356193897017860040811889729918311021171229845901641921068884387121855646124960798722908519296819372388642614839657382291123125024186649353143970137428531926649875337218940694281434118520158014123344828015051399694290153483077644569099073152433278288269864602789864321139083506217095002597389863554277196742822248757586765752344220207573630569498825087968928162753848863396909959826280956121450994871701244516461260379029309120889086942028510640182154399457156805941872748998094254742173582401063677404595741785160829230135358081840096996372524230560855903700624271243416909004153690105933983835777939410970027753472000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

4. 总结

使用递归函数的优点是逻辑简单清晰,缺点是过深的调用会导致栈溢出。针对尾递归优化的语言可以通过尾递归防止栈溢出。尾递归事实上和循环是等价的,没有循环语句的编程语言只能通过尾递归实现循环。Python标准的解释器没有针对尾递归做优化,任何递归函数都存在栈溢出的问题。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。