• Python中匿名函数和递归函数
  • 发布于 1个月前
  • 62 热度
    0 评论
  • 向日葵
  • 1 粉丝 9 篇博客
  •   
python 里面的大部分功能,都是通过函数来实现的。函数是基本单元和载体。它里面有哪些特别的地方呢?
函数体现了:“对自己狠一点”。
我可以没有名字,默默奉献,我叫无名氏(lambda)。(匿名函数)
“我无法改变别人,只好改变自己”。我自己调自己总可以了吧。(递归函数)
甘为人梯。函数作为参数给别人调用。(高阶函数)
也会闭门思过。(闭包函数)
偶尔也用外挂。(装饰器)

匿名函数
匿名函数的定义语法:
lambda 参数1,参数2,...,参数n:函数体
体验奉献精神之一:默默奉献
不管现实中给娃取名,还是代码中给对象取名。取名是个技术活。我们干脆简单一点,就叫无名氏。
匿名函数函数体只有一行代码,并且该行代码必须具有运行结果,运行结果会被作为函数的返回值自动返回(也可以实现只输出功能,但违背了Python简化代码的初衷,一般不建议使用)
匿名函数因为没有函数名,因此通常是通过变量接受该函数,之后通过变量名(参数列表)来调用。同时匿名函数因为代码只有一句,因此匿名函数一般只用来解决比较简单的数据计算问题
举个例子:
# 普通python函数def func(a,b,c):
    return a+b+c 
print func(1,2,3)# 返回值为6
 # lambda匿名函数
f = lambda a,b,c:a+b+cprint f(1,2,3)# 返回结果为6

好处是: 少写了个函数名字,少写了两行代码。

高阶函数
把函数作为参数传入,这样的函数称为高阶函数。
体验奉献精神之二: 甘为人梯

过滤函数filter
filter()也接收一个函数和一个序列。filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
例如,在一个list中,删掉偶数,只保留奇数,可以这么写:
list1=[1, 2, 4, 5, 6, 9, 10, 15]
def is_odd(n):
    return n % 2 == 1
result = filter(is_odd, list1)
print("筛选过后{}".format(list(result)))
接受组织挑选过后:
筛选过后[1, 5, 9, 15]
当然我们也可以用匿名函数:
list1=[1, 2, 4, 5, 6, 9, 10, 15]
# def is_odd(n):#     
    return n % 2 == 1
result = filter(lambda x: x % 2 == 1, list1)
print("筛选过后{}".format(list(result)))
映射map
map()函数接收两个参数,一个是函数,一个是序列,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回。
每个人都要为革命献身
举个例子:
假如现在收复台湾,每个人得捐献三个月工资和一袋米。
list1=[1, 2, 4, 5, 6, 9, 10, 15]
def denote(n):
    return str(n*3) + "一袋米"
result = map(denote, list1)
print("捐献过后{}".format(list(result)))
结果:
捐献过后['3一袋米', '6一袋米', '12一袋米', '15一袋米', '18一袋米', '27一袋米', '30一袋米', '45一袋米']
map有点像实现了一个for 循环。

归并函数reduce
reduce把一个函数作用在一个序列[x1, x2, x3...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算。用得比较少,掠过。

注意:
高阶函数的返回,是一个迭代器,如果要获取其中的值,需要转换成list.

递归函数
如果一个函数直接或间接的调用本身,这个函数即为递归函数

递归算法所体现的“重复”一般有三个要求:

(1)每次调用在规模上都有所缩小(通常是减半)
(2)是相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出作为后一次的输入)
(3)在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口,无条件递归调用将会成为死循环而不能正常结束。

注意:正确的递归函数都是有限定值的,即有递归次数的限制,不会无限递归下去。因此正确的递归函数需要设置结束位置。

我们来用愚公移山来解释递归。
第一个条件,假如愚公家100代能移走那座山。所以每一代后,留给下一代的任务就越来越少。(假设山不会长高)
第二个条件,愚公家族,每一代必须有联系,就是每一代都得生至少一个儿子,不能断了代。
第三个条件。就是总有一代是最后收尾的。第100代就能移完,可以退出移山的任务了。不能“子子孙孙无穷匮也!”
例子,这里最多的例子就是求阶乘:
def fact(n):
    if n==1:        
        return 1
    return n * fact(n - 1)
如果我们计算fact(5),可以根据函数定义看到计算过程如下:
===> fact(5)
===> 5 * fact(4)
===> 5 * (4 * fact(3))
===> 5 * (4 * (3 * fact(2)))
===> 5 * (4 * (3 * (2 * fact(1))))
===> 5 * (4 * (3 * (2 * 1)))
===> 5 * (4 * (3 * 2))
===> 5 * (4 * 6)
===> 5 * 24===> 120

闭包函数
闭包函数:在A函数内部定义另外一个函数B,之后B作为A函数的返回值直接被返回,此时函数B称为函数A的闭包函数。

官方定义是:闭包(closure)是函数式编程的重要的语法结构。函数式编程是一种编程范式 (而面向过程编程和面向对象编程也都是编程范式)。在面向过程编程中,我们见到过函数(function);在面向对象编程中,我们见过对象(object)。函数和对象的根本目的是以某种逻辑方式组织代码,并提高代码的可重复使用性(reusability)。闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性。
我们来看一个例子:
def line_conf(a, b):
    def line(x):
        return a*x + b    
    return line
line1 = line_conf(1, 1)
line2 = line_conf(4, 5)
print(line1(5), line2(5))
结果是:(6,25)
在闭包函数中如果使用了A函数中定义的变量,此时A函数中被定义的变量会被临时存储,直到B函数调用结束时,变量才会被系统回收,从而延长A中变量释放的时间。
理解不? 。

看我自己的理解:
假如我租了一个房子,需要退房,但是交房租在前,水电单子后面来。
我可以先交房租,然后交水电费。
我月中交的房租,房东就拿个小本本记着。月底水电费出来交水电费,房东就可以根据我交的所有钱,计算费用。重要的一点,无论我是否交清,房东都要告知我一声。
def fangzu(fee):
    print("交房租{}".format(fee))    
        def shuidian(fee1):
            print("交水电费{}".format(fee1))        
            if fee + fee1 == 5000:
                print("费用结清,可以滚蛋")        
            else:
                print("费用没结清!")    
         return shuidian
first=fangzu(4500) #先交房租
print(first) 
second = first(500) #后交水电费
结果:
交房租4500
<function fangzu.<locals>.shuidian at 0x10ef8fea0>
交水电费500
费用结清,可以滚蛋
这就体现中国古老思想,“分而治之”。先交一笔钱,记一笔账。后一笔秋后算账。但是前面的不能赖账。最终结果好歹也得有个通知。(必须有return)

装饰器
装饰器:装饰器的作用是,通过@语法直接用定义好的函数修饰之前已经存在的函数,从而实现对原函数功能的扩充

装饰器的优点
1.不需要修改原函数代码,即可实现对原函数功能的扩充
2.利于后期代码的维护
装饰器可以理解为外挂。
有了闭包,很容易理解装饰器。
比如我们要写一个对函数记录其log.
def log(func):
    def wrapper(*args,**kwargs):
        print("The function name is {}".format(func.__name__))        
        return func(*args,**kwargs)    
     return wrapper
@log
def say_good():
    print("hehe!")
say_good()
结果:

The function name is say_good
hehe!
如果我觉得可以更灵活一点
import datetime
def log(text):
    now1 = datetime.datetime.now()    
    if text == "start":
        print("start time:{}".format(now1))    
    def decorator(func):
        def wrapper(*args,**kwargs):
            print("The function name is {}".format(func.__name__))            
            return func(*args,**kwargs)
        now2 = datetime.datetime.now()
        print("end time:{}".format(now2))        
        if text == "detail":
        print("the run time is: {} microseconds".format((now2 - now1).microseconds))        
        return wrapper    
    return decorator
@log("start")
def say_good():
    print("hehe!")
@log("detail")
def say_hello():
    print("hello!")
say_good()
say_hello()
函数灵活运用,很多时候可以达到事半功倍的。
用户评论