Python基础-----函数式编程含义及特点(及尾递归)

一、定义
函数式就是用编程语言去实现数学函数。这种函数内对象是永恒不变的,要么参数是函数,要么返回值是函数,没for和while循环
所有的循环都由递归去实现,无变量的赋值(即不用变量去保存状态),无赋值即不可改变。
二、特点
1、不可变数据
不可变:不用变量保存状态,不修改变量

  • a. 非函数式

        a = 1
        def test():
            global a
            a += 1
            return a
        test()
        print(a)
        >>> 2
    
  • b. 函数式

          n = 1
          def test1(n):
              return n+1
          print(test1(2))
          print(n)
          >> 3
             1
    

2、第一类对象
第一类对象:函数即变量

  • a.函数名可以作为参数传递

          def a(n):
              print(n)
          def b(name):
              print('My name is %s'%name)
          a(b)
          # 上述调用为:b不带括号则表示b函数的内存地址,将内存地址作为实参传递给a函数,
          #则a函数打印的为b函数的内存地址
    
          a(b('Liming'))
          >>>'My name is Liming'   
              None
          #上述调用为:首先会执行函数b,则先打印出‘My name is Liming’,但是b函数没有定义返回值,
          #则默认为None
          #则将None作为实参传递给a函数,则a函数打印出None
    
  • b.返回值可以是函数名

          def a():
              print('from a')
          def b():
              print('from b')
              return a
          n = b()
          n()
          >>> 'from b'
              'from a'
    

3、尾调用优化(尾递归)

尾调用:在函数的最后一步调用另外一个函数(最后一行不一定是函数的最后一步)
尾调用优化:尾调用的关键就是在于函数的最后一步调用别的函数,这样的好处是:根据函数即‘变量’的定义,
定义a函数,a内调用b函数,b内调用c函数,在内存中会形成一个调用记录,又称调用帧,用于保存调用位置和内部变
量等信息,即a->b->c直到c返回结果给b,c的调用记录才会消失,b返回给a,b的调用记录消失,a返回结果,a的调用记录消失,所有的调用记录都是先进后出,形成了一个调用栈。尾调用由于是函数的最后一步操作,所以不需要保留外
层函数的调用记录,因为调用位置、内部变量等信息都不会用到了,只要直接用内层函数的调用记录,取代外层函数的
调用记录就可以了。

    def bar(n)
        return n
    def foo(x):
        return bar(x)
    print(foo(3))
    >>> 3

上述foo(3)就等于bar(3),也就是说foo在最后一步调用了bar,然后foo的调用记录就清楚了,剩下的就是bar
自己的事情了。所以内存里永远只保留一个调用记录。
尾递归:函数调用自身成为递归,如果尾调用自身,就成为尾递归。
尾递归特点:重复相同的事情,每次重复会使问题规模减少。
尾递归举例:
问题:师傅,北京怎么去啊?
解决方法:a去问b,b不知道,b去问c,c去问d,最有由d得出结果,此过程可以发现,问题最有只需要d去
结局即可,a b c都无需保存任何记录,不干事,因为他们啥都不知道。
尾递归优点:递归通常非常耗费内存,因为需要同时保存成千上百个调用记录,很容易发生‘栈溢出’错误。
但对于尾递归来说,由于只存在一个调用记录,所以不会发生‘栈溢出’错误。

    def cal(l):
        print(l)
        if len(l) == 1:
            return l[0]
        first,second,*args = l
        l[0] = first + second
        l.pop(1)
        return cal(l)
    x = cal([i for i in range(10)])
    print(x)
    >>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
        [1, 2, 3, 4, 5, 6, 7, 8, 9]
        [3, 3, 4, 5, 6, 7, 8, 9]
        [6, 4, 5, 6, 7, 8, 9]
        [10, 5, 6, 7, 8, 9]
        [15, 6, 7, 8, 9]
        [21, 7, 8, 9]
        [28, 8, 9]
        [36, 9]
        [45]
        45
    上例就是用到尾递归,最终求得1~9的和
尾递归虽然很好,但是经测试和网上求证,python并没有对尾递归进行优化,递归深度超过1000就会报错
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一、快捷键 ctr+b 执行ctr+/ 单行注释ctr+c ...
    o_8319阅读 5,881评论 2 16
  • 一、Python简介和环境搭建以及pip的安装 4课时实验课主要内容 【Python简介】: Python 是一个...
    _小老虎_阅读 5,848评论 0 10
  • Python语言特性 1 Python的函数参数传递 看两个如下例子,分析运行结果: 代码一: a = 1 def...
    伊森H阅读 3,095评论 0 15
  • 清代诗人郑板桥《墨竹图题诗》衙斋卧听萧萧竹,疑似民间疾苦声。些小吾曹州县吏,一枝一叶总关情。这首诗充分体现了郑板桥...
    村夫_3183阅读 1,075评论 9 58
  • 按现在的说法,我大哥二哥三哥都属50后,我和弟弟大妹属60后,小妹属70后。 父亲五十年代初就离开老家分...
    沧桑梦破阅读 758评论 1 0