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

前言

这是 “Python 基础”系列的第 03 篇文章 ,共 20 篇 。 01 Python 基础:Python入门必看之语法基础 02 Python 基础:列表及字典内置函数&方法内容梳理 03 Python 基础:Python函数及递归函数知识点梳理 04 Python 基础:讲解迭代、过滤、匿名函数、排序算法四大知识点 05 Python 基础:高阶函数学习实践 06 Python 基础:难点装饰器的学习介绍及实现赌博收益小案例 07 Python 基础:重点知识点函数的参数难点解答 08 Python 基础:面试问你类与实例及其属性还不会吗 09 Python 基础:手把手带你梳理对象、继承与多态知识点 10 Python 基础:如何定制类,这里有答案 11 Python 基础:知识巩固,实现一个简易学生管理系统 12 Python 基础:如何优化代码质量,错误、调试和测试你必须要懂 13 Python 基础:模块的概念及使用方法并着重介绍两个常用模块 14 Python 基础:重点知识点--IO编程 15 Python 基础:程序猿必懂知识之正则表达式 16 Python 基础:重点知识点--Pygame的基础知识梳理 17 Python 基础:重点知识点--Pygame实现儿时经典游戏坦克大战 18 Python 基础:重点知识点--进程和线程概念、应用知识梳理 19 Python 基础:重点知识点--网络通信基础知识讲解 20 Python 基础:重点知识点--网络通信进阶知识讲解

目录

3 Python 基础: Python函数及递归函数知识点梳理,共有 2 部分:

  • 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标准的解释器没有针对尾递归做优化,任何递归函数都存在栈溢出的问题。

本文分享自微信公众号 - 离不开的网(Gy_dxj)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-09-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏小海怪python学习

解决新版Pycharm中Matplotlib图像不在弹出独立的显示窗口问题

https://intellij-support.jetbrains.com/hc/en-us/community/posts/115000736584-Sci...

16510
来自专栏LhWorld哥陪你聊算法

大白话5分钟带你走进人工智能-第36节神经网络之tensorflow的前世今生和DAG原理图解(4)

Tensorflow由Google Brain谷歌大脑开源出来的,在2015年11月在GitHub上开源,2016年是正式版,2017年出了1.0版本,趋于稳定...

9930
来自专栏FunTester

Python使用plotly生成本地文件教程

本人在学习使用Python和plotly处理数据的过程中,发现了官网教程和网上一些教程无法正常使用的情况,可能是因为更新导致的,所以我在尝试成功之后想自己写一个...

13040
来自专栏小海怪python学习

python高级编程第一讲:深入类和对象

多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚"鸭子类型"

8040
来自专栏大数据实战演练

Ambari 自定义服务启动成功后,依旧显示停止状态的解决方案

如果遇到该情况,首先前往 /var/log/ambari-agent/ambari-agent.log 查看日志输出。

23320
来自专栏小海怪python学习

win 10 下多个python环境pip安装时默认环境的变更

最开始的时候我的电脑上只安装了一个python 3.6 的环境,此时pip安装时候路径正常,后面为了学习pyqt5又安装了Anaconda3的集成环境,然后我发...

12940
来自专栏小海怪python学习

python 基础知识第3讲:基本数据类型

表达式是由数据、算符、数字分组符号()、自由变量和约束变量等以能求得数值的有意义的排列方法所得的组合(类似于数学的公式)。

7920
来自专栏崔庆才的专栏

Heartrate:如追综心跳般实时动态可视化监测 Python 程序运行

项目地址:https://github.com/alexmojaki/heartrate

21330
来自专栏Pou光明

Qt使用C/C++扩展Python内置模块

之前和大家介绍过在C/C++中嵌入Python,本次和大家分享下使用C/C++扩展Python内置模块的方法。

15510
来自专栏小海怪python学习

python 基础知识第2讲:python要点

computer language:用于人与计算机之间的通信。 由字符、数字、语法规则组成。

9520

扫码关注云+社区

领取腾讯云代金券

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