零基础入门学Python(六)—— 函数(下)
2021/4/24 14:55:15
本文主要是介绍零基础入门学Python(六)—— 函数(下),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
零基础入门学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 “
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 “
这个报错信息跟之前全局变量的时候基本一样,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 “
这个例子是初学者使用递归时最容易出现的错误,从理论上说,这个程序将永远执行下去直至耗尽所有内存资源。不过Python3处于“善意的保护”,对递归的深度默认限制是100层,所以我们的代码才会停下来。不过如果写网络爬虫等工具,可能会爬很深,那么我们可以自己设置递归的深度限制。方法如下:
example2: >>>import sys
>>>sys.setrecursionlimit(1000000) # 将递归限制设置为100万层
例1:写一个求阶乘的函数。
- 非递归版本
def recursion(n): result = n for i in range(1, n): result *= i return result number = int(input('请输入一个整数:'))result = recursion(number)print("%d的阶乘是:%d" % (number, result))
程序实现结果如下:
请输入一个整数:10
10的阶乘是:3628800
- 递归版本
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) 设置了正确的返回条件。
递归的实现可以是函数自身调用自身,每次函数的调用都需要进行压栈、弹栈、保存和恢复寄存器的栈操作,所以在这上边是非常消耗时间和空间的。另外,如果递归一旦忘记了返回,或者错误地设置了返回条件,那么执行这样的递归代码就会变成一个无底洞:只进不出!但是当递归用在妙处的时候,可以使代码简洁、精练。
例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 a3 n=int(input("请输入经过的月份:"))result = fab(n)if result != -1: print('总共有%d对小兔子诞生!'% result)
- 递归实现
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(六)—— 函数(下)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-05-08有遇到过吗?同样的规则 Excel 中 比Python 结果大
- 2024-03-30开始python成长之路
- 2024-03-29python optparse
- 2024-03-29python map 函数
- 2024-03-20invalid format specifier python
- 2024-03-18pool.map python
- 2024-03-18threads in python
- 2024-03-14python Ai 应用开发基础训练,字符串,字典,文件
- 2024-03-13id3 algorithm python
- 2024-03-13sum array elements python