零基础入门学Python(六)—— 函数(下)

零基础入门学Python(六)—— 函数(下),第1张

概述零基础入门学Python系列内容的学习目录→\rightarrow→零基础入门学Python系列内容汇总。函数(下)1.Python的乐高积木2.灵活即强大3.我的地盘听我的4.内嵌函数和闭包

零基础入门学Python系列内容的学习目录 → \rightarrow →零基础入门学Python系列内容汇总。

函数(下)1. Python的乐高积木2. 灵活即强大3. 我的地盘听我的4. 内嵌函数和闭包4.1 global关键字4.2 内嵌函数4.3 闭包(closure)5. lambda表达式6. 递归7. 介绍两个BIF:filter()和map()

  需要学习的基础知识有:函数、参数、闭包、lambda表达式、递归等。因本部分内容较多,故分为上下两个篇章。
    1、2、3部分内容见零基础入门学Python(六)—— 函数(上)
    4、5、6、7部分内容见零基础入门学Python(六)—— 函数(下)

1. Python的乐高积木 2. 灵活即强大 3. 我的地盘听我的

  前半部分内容见零基础入门学Python(六)—— 函数(上)。

4. 内嵌函数和闭包 4.1 global关键字

  全局变量的作用域是整个模块(整个代码段),也就是代码段内所有的函数内部都可以访问到局部变量。但要注意的一点是,在函数内部仅仅去访问全局变量就好,不要试图去修改它。因为那样的话,Python会使用屏蔽(Shadowing)的方式“保护”全局变量:一旦函数内部试图修改全局变量,Python就会在函数内部自动创建一个名字一模一样的局部变量,这样修改的结果只会修改到局部变量,而不会影响到全局变量。看下面的例子:

  example1: >>>count = 5
        >>>def myFun():
            count = 10
            print(count)

       >>>myFun()
       10
       >>>count
       5

  在函数中修改全局变量可能会导致程序可读性变差、出现莫名其妙的BUG、代码的维护成本提高,但仍然觉得有必要在函数中去修改这个全局变量的情况下,那么不妨可以使用global关键字来达到目的。修改程序如下:

  example2: >>>count = 5
        >>>def myFun():
            global count
            count = 10
            print(count)

       >>>myFun()
       10
       >>>count
       10

4.2 内嵌函数

  Python的函数定义是可以嵌套的,也就是允许在函数内部创建另一个函数,这种函数叫作内嵌函数或者内部函数。看一个例子:

  example1: >>>def fun1():
            print(" fun1()正在被调用…")
            def fun2():
               print(" fun2()正在被调用…")
            fun2()

       >>> fun1()
       fun1()正在被调用…
       fun2()正在被调用…

  内部函数整个作用域都在外部函数之内,即上面例子中的fun2()整个函数的作用域都在fun1()里边。需要注意的地方是,除了在fun1()这个函数体中可以随意调用fun2()这个内部函数外,出了fun1()就没有任何可以对fun2()进行的调用。如果在fun1()外部试图调用内部函数fun2(),就会报错:

       >>> fun2()
       Traceback (most recent call last):
        file “<pyshell#38>”, line 1, in < module >
         fun2()
       nameError: name ‘fun2’ is not defined

4.3 闭包(closure)

  闭包(closure)是函数式编程的一个重要的语法结构,函数式编程是一种编程范式,著名的函数式编程语言就是liSP语言。Python中的闭包从表现形式上定义为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。看个例子:

  example1: >>>def funX(x):
            def funY(y) :
               return x * y
            return funY

       >>> i = funX(8)
       >>> i(5)
       40

  也可以直接写为:

       >>> i = funX(8)(5)
       40

  通过上面的例子理解闭包的概念:如果在一个内部函数里(funY就是这个内部函数)对外部作用域(但不是在全局作用域)的变量进行引用(x就是被引用的变量,x在外部作用域funX函数里面,但不在全局作用域里),则这个内部函数(funY)就是一个闭包。
  使用闭包需要注意的是:因为闭包的概念就是由内部函数而来的,所以我们也不能在外部函数以外的地方对内部函数进行调用,下面的做法是错误的:

       >>> funY(5)
       Traceback (most recent call last):
        file “< pyshell#39>”, line 1, in < module >
         funY(5)
       nameError: name ‘funY’ is not defined

  在闭包中,外部函数的局部变量对应内部函数的局部变量,事实上相当于之前的全局变量跟局部变量的对应关系。在内部函数中,只能对外部函数的局部变量进行访问,但不能进行修改。

  example2: >>>def funX( ):
            x = 5
            def funY( ) :
               x *= x
               return x
            return funY

       >>>funX( )( )
       Traceback (most recent call last):
        file “<pyshell#7>”, line 1, in < module >
         funX()()
        file “<pyshell#6>”, line 4, in funY
         x *= x
       UnboundLocalError: local variable ‘x’ referenced before assignment

  这个报错信息跟之前全局变量的时候基本一样,Python认为在内部函数的x是局部变量的时候,外部函数的x就被屏蔽了起来,所以执行x *= x的时候,在右边根本就找不到局部变量x的值,因此报错。
  在python3以前并没有直接的解决方案,只能间接地通过容器类型来存放,因为容器类型不是放在栈里,所以不会被“屏蔽”掉。之前学习的字符串、列表、元组都可以往里的放的就是容器类型,于是可以把代码修改为如下:

  example3: >>>def funX( ):
            x = [ 5 ]
            def funY( ) :
               x[ 0 ] *= x[ 0 ]
               return x[ 0 ]
            return funY

       >>>funX( )( )
       25

  到了python3中,如果希望内部函数里可以修改外部函数里的局部变量的值,那么可以使用nonlocal关键字:

  example4: >>>def funX( ):
            x = 5
            def funY( ) :
               nonlocal x
               x *= x
               return x
            return funY

       >>>funX( )( )
       25

5. lambda表达式

  Python允许使用lambda关键字来创建匿名函数。

  example1: >>>def ds(x):
            return 2 * x + 1

       >>>ds(5)
       11

  如果使用lambda语句来定义这个函数:

  example2: >>>lambda x : 2 * x + 1
       <function < lambda > at 0x000002BBE5C75048>

  Python的lambda表达式语法非常精简,基本语法是在冒号( : )左边放原函数的参数,可以有多个参数,用逗号( ,)隔开即可,冒号右边是返回值。lambda语句返回的是一个函数对象,如果要对它进行使用,只需要进行简单的赋值 *** 作即可:

  example3: >>>g = lambda x : 2 * x + 1
       >>> g(5)
       11

  下面是lambda表达式带两个参数的例子:

  example4: >>> def add(x, y):
           return x + y

        >>> add(3, 4)
        7
        >>> # 把它转换为lambda表达式:
        >>>g = lambda x, y : x + y
        >>>g(3, 4)
        7

  lambda表达式的作用:

Python写一些执行脚本时,使用lambda就可以省下定义函数过程,使得代码更加精简;对于一些比较抽象并且整个程序执行下来只需要调用一两次的函数,使用lambda就不需要考虑命名的问题;简化代码的可读性,由于阅读普通函数经常要跳到开头def定义的位置,使用lambda函数可以省去这样的步骤。6. 递归

  递归从原理上来说就是函数调用自身的行为。

  example1: >>>def recursion():
           recursion()

       >>> recursion()
       Traceback (most recent call last):
        file “<pyshell#8>”, line 1, in < module >
         recursion()
        file “<pyshell#7>”, line 2, in recursion
         recursion()
        file “<pyshell#7>”, line 2, in recursion
         recursion()
        file “<pyshell#7>”, line 2, in recursion
         recursion()
        [PrevIoUs line repeated 990 more times]
       RecursionError: maximum recursion depth exceeded

  这个例子是初学者使用递归时最容易出现的错误,从理论上说,这个程序将永远执行下去直至耗尽所有内存资源。不过python3处于“善意的保护”,对递归的深度默认限制是100层,所以我们的代码才会停下来。不过如果写网络爬虫等工具,可能会爬很深,那么我们可以自己设置递归的深度限制。方法如下:

  example2: >>>import sys
        >>>sys.setrecursionlimit(1000000) # 将递归限制设置为100万层

  例1:写一个求阶乘的函数。

非递归版本
def recursion(n):    result = n    for i in range(1, n):        result *= i    return resultnumber = int(input('请输入一个整数:'))result = recursion(number)print("%d的阶乘是:%d" % (number, result))

  程序实现结果如下:
  
  请输入一个整数:10
  10的阶乘是:3628800

递归版本

图1 递归函数的是实现分析
def factorial(n):     if n == 1:         return 1     else:        return n * factorial(n-1)number = int(input('请输入一个整数:'))result = factorial(number)print("%d的阶乘是:%d" % (number,result))

  程序实现结果如下:
  
  请输入一个整数:10
  10的阶乘是:3628800

  上面这个例子满足了递归的两个条件:
   (1) 调用函数本身。
   (2) 设置了正确的返回条件。
  递归的实现可以是函数自身调用自身,每次函数的调用都需要进行压栈、d栈、保存和恢复寄存器的栈 *** 作,所以在这上边是非常消耗时间和空间的。另外,如果递归一旦忘记了返回,或者错误地设置了返回条件,那么执行这样的递归代码就会变成一个无底洞:只进不出!但是当递归用在妙处的时候,可以使代码简洁、精练。

  例2:用递归实现斐波那契数列。

迭代实现
def fab(n):    a1 = 1    a2 = 1    a3 = 1    if n < 1:        print("输入有误!")        return -1    while (n-2) > 0:        a3 = a1 + a2        a1 = a2        a2 = a3        n -= 1    return a3n=int(input("请输入经过的月份:"))result = fab(n)if result != -1:    print('总共有%d对小兔子诞生!'% result)
递归实现

图2 递归实现斐波那契数列的原理
def fab(n):    if n < 1:        print("输入有误!")        return -1    if n == 1 or n == 2:        return 1    else:        return fab(n-1) + fab(n-2)n = int(input("请输入经过的月份:"))result = fab(n)if result != -1:    print('总共有%d对小兔子诞生!'% result)

  可以看出使用递归实现逻辑非常简单,但是当我们把n设为35时,程序执行起来就非常耗时了,而此时用迭代代码实现基本上是毫秒级的。

7. 介绍两个BIF:filter()和map() 1. filter()
  filter()内建函数是一个过滤器,通过过滤器可以保留我们所关注的信息,把其他不感兴趣的东西直接丢掉。
   >>> help(filter)


   filter有两个参数,第一个参数可以是一个函数也可以是None,如果是一个函数的话,则将第二个可迭代数据里的每一个元素作为函数的参数进行计算,把返回True的值筛选出来; 如果第一个参数为None,则直接将第二个参数中为True的值筛选出来。
  example1: >>> temp = filter(None, [1, 0, False, True])
        >>>List(temp)
        [1, True]
  利用filter(),尝试写一个筛选奇数的过滤器:
  example2: >>> def odd(x):
            return x % 2
        >>> temp = filter(odd, range(10))
        >>> List(temp)
        [1, 3, 5, 7, 9]
  学习lambda表达式后,可以把上述过程转化成一行:
  example3: >>>List(filter(lambda x : x % 2, range(10)))
        [1, 3, 5, 7, 9]2. map()
  在编程领域,map一般作“映射”来解释。map()这个内置函数也有两个参数,仍然是一个函数和一个可迭代序列,将序列的每一个元素作为函数的参数进行运算加工,直到可迭代序列的每个元素都加工完毕,返回所有加工后的元素构成的新序列。
  example4: >>> List(map(lambda x : x * 2, range(10)))
        >>>List(temp)
        [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] 总结

以上是内存溢出为你收集整理的零基础入门学Python(六)—— 函数(下)全部内容,希望文章能够帮你解决零基础入门学Python(六)—— 函数(下)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1186144.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-03
下一篇 2022-06-03

发表评论

登录后才能评论

评论列表(0条)

保存