3 Python 基础: Python函数及递归函数知识点梳理

Python函数

函数的英文是function,所以,通俗地来讲,函数就是功能的意思。函数是用来封装特定功能的,比如,在Python里面,len()是一个函数,len()这个函数实现的功能是返回一个字符串的长度,所以说len()这个函数他的特定功能就是返回长度,再比如,我们可以自己定义一个函数,然后编写这个函数的功能,之后要使用的时候再调用这个函数。所以函数分为两种类型,一种是系统自带的不用我们编写其功能系统自己就有的,比如len()这种函数,另一种函数是我们自定义的,需要我们编写其功能的,这种函数自由度高,叫做自定义函数,需要使用的时候直接调用该函数。

Python里函数的定义

在Python中要想使用自定义函数,就得首先定义一个函数,定义一个函数包括两个部分的含义,第一个含义是申明这个指定的部分是函数,而不是其他的对象,第二个含义是要定义这个函数所包含的功能,也就是要编写这个函数的功能。

def 函数名():

    函数内容;函数内容

    函数内容;函数内容
### 1+2+3+5+6+...+n
#1+2+3...+10
allNum = 0
for i in range(1,11):
    allNum = allNum + i;
print(allNum)


#1+2+3...+100
allNum = 0
for i in range(1,101):
    allNum = allNum + i;
print(allNum)


#写一个可以调用的函数,只要传入一个参数N,就可以返回1+2+3+5+6+...+n的结果
def addNum(n):
    allNum = 0
    for i in range(1,n+1):
        allNum = allNum + i;
    print(allNum)
    return allNum
    #return None

addNum(200)
addNum(100)
bb = addNum(10)
print(bb)

#def 函数名(函数的参数):
    #缩进一个TAB按键的代码块



#结果为
55
5050
20100
5050
55
55

形参与实参

参数的传递

在Python中函数在调用的过程中参数的传递使用顺序的。

关键字参数

关键字参数有两大好处。首先,它们清晰地指出了参数值,有助于提高程序的可读性;其次,关键字参数的顺序无关紧要。对于包含大量参数的函数来说,这两点都很有帮助,因为很难记住这些函数的参数的顺序和含义。

3、全局变量与局部变量

什么是作用域

Python中一个变量的是在一定的范围内起作用的,在其起作用的这个范围我们称之为作用域。

全局变量与局部变量两者的本质区别就是在于作用域

用通俗的话来理解的话,

全局变量是在整个py文件中声明,全局范围内都可以访问

局部变量是在某个函数中声明的,只能在该函数中调用它,如果试图在超出范围的地方调用,程序就爆掉了

如果在函数内部定义与某个全局变量一样名称的局部变量,就可能会导致意外的效果,可能不是你期望的。因此不建议这样使用,这样会使得程序很不健全

直接来看几个例子来理解全局变量和局部变量的区别吧:

Demo1:

def fun(x):  
    y=2  
    print("乘法的运行结果:",x*y)  

num1=1  
print("初始num1=",num1)  
fun(num1)  
print("y的值是:",y)  

运行结果:

报错的原因是因为试图访问局部变量,但是访问的地方不在该变量y的作用域中

Demo2:

def fun():  
    num1=2  
    print("函数内修改后num1=",num1)  

num1=1  
print("初始num1=",num1)  
fun()  

print("运行完函数后num1=",num1)

运行结果:

可以看到在函数内部对全局变量的修改后,在函数执行完毕,修改的结果是无效的,全局变量并不会受到影响

再看:

Demo3:

def fun():  
    num1*=2  
    print("函数内修改后num1=",num1)  

num1=1  
print("初始num1=",num1)  
fun()  

print("运行完函数后num1=",num1)  

运行结果:

报错了。这是因为在fun()函数使用了局部变量num1,它只是个跟全局变量同名的局部变量,使用前还是要赋值,因此再次强调不要这样使用

global关键字

如果真的想要在函数体内修改全局变量的值,就要使用global关键字

Demo4:

def fun():  
    global num1  
    num1=2  
    print("函数内修改后num1=",num1)  

num1=1  
print("初始num1=",num1)  
fun()  

print("运行完函数后num1=",num1)

运行结果:

使用global关键字就是告诉python编译器这个变量不是局部变量而是全局变量,其实有点像是"引用"的意思

nonlocal关键字

再看看另一个跟变量相关的关键字nonlocal,字面意思就是指当前的这个变量不是局部变量。nonlocal是Python3.0中新增的关键字,python2.x不支持

先来看看下面这段代码

def fun():  
    num2=3  
    def fun2():  
        num2*=2  
        print("num2=",num2)  
    return fun2()  
  
fun()

运行结果:

错误的原因跟前面的差不多,就是使用了未定义的局部变量,然而num2也不是全局变量,只是fun2函数的外层变量,强行使用global定义num2的话同样会报错(不信你试试)

这时候需要使用nonlocal关键字:

def fun():  
    num2=3  
    def fun2():  
        nonlocal num2  
        num2*=2  
        print("num2=",num2)  
    return fun2()  
  
fun()  

运行结果:

如此,程序就能正常执行

4、函数的使用与返回值

函数的返回值

在Python中有的函数是有返回值的,有的函数是没有返回值的。而有返回值的函数,我们让函数可以返回一个值,也可以让函数返回多个值。

5、文档字符串

Python 递归函数

在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。

举个例子,我们来计算阶乘n! = 1 x 2 x 3 x ... x n,用函数fact(n)表示,可以看出:

fact(n) = n! = 1 x 2 x 3 x ... x (n-1) x n = (n-1)! x n = fact(n-1) x n

所以,fact(n)可以表示为n x fact(n-1),只有n=1时需要特殊处理。

于是,fact(n)用递归的方式写出来就是:

如果我们计算fact(5),可以根据函数定义看到计算过程如下:

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

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

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

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

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

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

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

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

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

小结

使用递归函数的优点是逻辑简单清晰,缺点是过深的调用会导致栈溢出。

针对尾递归优化的语言可以通过尾递归防止栈溢出。尾递归事实上和循环是等价的,没有循环语句的编程语言只能通过尾递归实现循环。

Python标准的解释器没有针对尾递归做优化,任何递归函数都存在栈溢出的问题。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Python绿色通道

良心整理!学习Python数据分析的正确姿势

原文地址:How to Learn Python for Data Science the Right Way

22840
来自专栏华章科技

从0到1,手把手教你如何使用哈工大NLP工具——PyLTP

LTP(Language Technology Platform)中文为语言技术平台,是哈工大社会计算与信息检索研究中心开发的一整套中文语言处理系统。

37120
来自专栏华章科技

49个Python学习资源:从初学者到高级玩家都有了

3. Basic Data Types in Python – Real Python

11620
来自专栏python学习教程

python爬虫学习教程,批量抓取美女图片!

python的抓取功能其实是非常强大的,当然不能浪费,呵呵。下面就与大家分享一个python写的美女图自动抓取程序吧!

12830
来自专栏技术探究-前端、Python、爬虫、数据分析、工具

爬虫系列(10)Scrapy 框架介绍、安装以及使用。

运行命令:scrapy startproject myfrist(your_project_name)

11540
来自专栏python学习教程

python如何自学?python学习技巧

Python现在非常火,语法简单而且功能强大,很多同学都想学Python!所以小的给各位看官们准备了高价值Python学习视频教程及相关电子版书籍,欢迎前来领取...

14120
来自专栏技术探究-前端、Python、爬虫、数据分析、工具

爬虫系列(1)第一步肯定是先介绍介绍爬虫。

网络爬虫也叫网络蜘蛛,如果把互联网比喻成一个蜘蛛网,那么蜘蛛就是在网上爬来爬去的蜘蛛,爬虫程序通过请求url地址,根据响应的内容进行解析采集数据,比如:如果响应...

12530
来自专栏技术探究-前端、Python、爬虫、数据分析、工具

爬虫系列(11)Scrapy 数据的提取和保存以及Pipeline的介绍。

从网页中提取数据,Scrapy 使用基于 XPath 和 CSS 表达式的技术叫做选择器。以下是 XPath 表达式的一些例子:

32430
来自专栏编程之路的专栏

Python 编程技巧之字符串拼接

这样写不仅代码不好看,而且性能也不高。实际上,在Python中,字符串的拼接有多种实现方法,这里就一一介绍一下,并简单的测试其性能

9720
来自专栏Bingo的深度学习杂货店

Leetcode【46、47、89、357、659】

同上面的 Leetcode 46,使用 DFS 回溯法。需要用集合 set 保存结果,然后再加入到集合前判断之前是否出现过。最后,将集合转化为列表输出即可。

7520

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励