Python函数与码复用

一.函数的定义与使用

1.函数的定义与使用方法

函数是一段代码的表示,它对应了一段具有特定功能的、可重用的语句组,它是一种功能的抽象,它表达特定的含义。在一般编程中,函数有两个作用,它通过函数定义一段功能,可以降低编码难度,同时也可以对一段代码进行复用。

函数的使用方法如下,其中函数体指的是函数内部包含的一些语句代码:

def <函数名>(<参数(0个或多个)>):
    <函数体>
    return <返回值>

实例:计算n!

def fact(n):
    s=1
    for i in range(1,n+1):
        s*=i
    return s

函数在定义时,所指定的参数只是一种占位符,它是一种符号表示。函数定义之后,如果这个函数不被调用,那么这个函数在程序中也是不会被执行,即函数被调用才会执行。

从另外一个角度来理解函数,函数在定义时给定参数,参数就是函数的输入,函数体本身就是对参数的一种处理,而return就是给出这段函数运行的结果,可以看到有输入、处理和输出,这就是IPO。可以简单理解函数就是IPO的一种实现,函数也是一段完整代码的封装。

2.函数的使用以及调用过程

函数的调用指的是运行函数代码的方式,例如上面的实例计算n!,程序看到这段定义并不会去执行这段代码,而执行需要使用函数的调用方式。所谓调用就是用函数的名称给定一个具体的值作为参数,所以调用时给出的实际参数是运行函数的输入,要用实际的参数替换定义中的占位参数,函数调用后会得到实际参数运行之后的运行结果。

以如下代码为例,说明调用过程:
在这里插入图片描述
首先,程序会查找定义的函数fact,并将给定的参数10赋给这个函数的占位参数n,此时10就代替了定义函数中的n。然后执行函数体相关的程序,那么运算这段代码之后产生了一个具体的s值。接着这个具体的s值会被作为返回值返回给fact(10)的这段代码,作为运算结果并赋值给变量a。最后print(a)之后,得到了整个10!的运算结果。

这就是一个函数的调用过程

3.函数的参数传递

其实函数可以有参数,也可以没有参数,但是无论函数定义时有没有参数都必须保留这个括号,如果没有参数直接给个空括号,格式如下(没有参数):

def <函数名>():
    <函数体>
    return <返回值>

此外,在函数定义时也可以为某些参数指定一个默认值,构成可选参数。可选参数就是在调用函数时,某些可以提供也可以不提供的参数。Python中要求在定义函数时,所有的可选参数必须放在必选参数之后,这是一种约定。

此时的格式如下:

def <函数名>(<必选参数>,<可选参数>):
    <函数体>
    return <返回值>

说明:可选参数格式为<参数名称>=<默认值>,例如:

def fact(n,m=1):
    s=1
    for i in range(1,n+1):
        s*=i
    return s//m

在上面这个函数中,m就是可选参数,默认值为1。当调用参数fact(10)时,返回3628800;当调用参数fact(10,5)时,返回725760。这叫可选参数传递。

此外在参数传递中,还有一种叫可变参数传递,也就是说在定义函数时,可以设计函数接收的参数时可变数量的,即不确定参数总数量。

此时的格式如下:

def <函数名>(<参数>,*<参数>):
    <函数体>
    return <返回值>

例如:

def fact(n,*m):
    s=1
    for i in range(1,n+1):
        s*=i
    for j in m:
        s*=j
    return s

在上面这个函数中,m就是可变参数。当调用参数fact(10,3)时,返回10886400;当调用函数fact(10,3,5,8)时,返回435456000;甚至可以给出更多的参数。

说到可变参数传递就不能不说max()函数和min()函数,他们就是使用可变参数来进行参数的定义。

参数的传递指的是在函数调用时,参数可以按照位置或名称方式传递。这里以可选参数的例子进行说明:

def fact(n,m=1):
    s=1
    for i in range(1,n+1):
        s*=i
    return s//m

可以使用fact(10,5)调用函数,使用的是位置传递,10对应占位参数n,5对应占位参数m。也可以使用fact(m=5,n=10)调用函数,使用的是名称传递,直接指定占位参数的实际值。

4.函数的返回值

函数可以返回0个或多个结果,其中使用保留字return来传递返回值。但其实函数可以有返回值,也可以没有,可以使用保留字return,也可以不使用。一段函数如果不想返回任何值,可以给出return但不加任何的返回信息,也可以不适用return,所以return并不是定义函数的必要保留字。return可以传递0个返回值,也可以传递任意多个返回值。

例如:

def fact(n,m=1):
    s=1
    for i in range(1,n+1):
        s*=i
    return s//m,n,m

当使用fact(10,5)调用函数时,那么将返回(725760, 10, 5),返回值使用小括号包裹中间用逗号隔开的形式来体现,即元组类型。当然在使用过程中,也可以用对应数量的变量名来分别获取函数的返回值,将返回值赋值给变量,例如a,b,c=fact(10,5),那么a=725760,b=10,c=5。

5.局部变量和全局变量

局部变量是函数内部使用的变量,而函数外部整个程序使用的变量叫全局变量。例如:

n,s=10,100  #这里的n和s是全局变量
def fact(n):  #这里的n是局部变量
    s=1  #这里的s是局部变量
    for i in range(1,n+1):
        s*=i
    return s
print(fact(n),s)  #这里的n和s是全局变量

在函数中,无论是参数还是内部使用的变量都是局部变量。

局部变量和全局变量的使用规则有两点。第一点,局部变量和全局变量是不同的变量,局部变量是函数内部的占位符,与全局变量可能重名但不同。并且在函数运算结束后局部变量被释放,也就是说这个变量将不再存在。当然可以使用保留字global在函数内部使用全局变量。这里举一个在函数内部使用全局变量的例子,如下:

n,s=10,100
def fact(n):
    global s  #声明此处s是全局变量s
    for i in range(1,n+1):
        s*=i
    return s
print(fact(n),s)  #此时输出的s已经被函数修改

第二点,如果局部变量是组合数据类型(序列类型(字符串、元组、列表)、集合类型(集合)、映射类型(字典)),而且未在函数内部创建,那么它就是全局变量。例如:

ls=["F","f"]  #创建一个全局变量列表ls
def func(a):
    ls.append(a)  #此处ls是列表类型,并且未在函数内部创建,则等同于全局变量
    return
func("C")  #全局变量ls被修改
print(ls)  #输出结果['F','f','C']

当在函数内部创建组合数据类型是,如下:

ls=["F","f"]  #创建一个全局变量列表ls
def func(a):
    ls=[]  #此处真实创建了局部变量列表ls
    ls.append(a)
    return   #Python小白学习交流群:725638078
func("C")  #局部变量ls被修改,而全局变量ls没有被修改
print(ls)  #输出结果['F','f']

这样造成的原因是:在Python中组合数据类型是由指针来体现的,所以函数中如果没有真实创建组合数据类型,它使用的变量是使用的指针,而指针是外部的全局变量,所以在修改这个指针对应的内容时就修改了全局变量。

6.lambda函数

lambda函数能够返回一个函数名作为结果,简单来说lambda函数是一种匿名函数。它使用lambda保留字来定义,函数名就是返回结果。lambda函数仅用于定义一种简单的,能够在一行内表达实现的一种函数。使用格式如下:

<函数名>=lambda <参数>:<表达式>
#等价于
def <函数名>(<参数>):
    <函数体>
    return <返回值>

注意:lambda函数后面只能使用表达式,而不能使用函数体。

实例:

>>> f=lambda x,y:x+y
>>> f(10,15)
25

当然lambda函数也可以接收没有参数的函数,例如:

>>> f=lambda :"lambda函数"
>>> f()
'lambda函数'
>>> print(f())
lambda函数

一般在编写代码时,哪怕这个函数只有一行,也建议使用def和return这种方法来定义,要谨慎使用lambda函数。

lambda函数不是定义函数的常用形式,它的存在主要是用作一些特定的函数或方法的参数,有一些非常复杂的函数,它的某一个参数就是一个函数,这种情况下使用lambda函数。

lambda函数有一些固定使用方法,建议逐步掌握。一般情况下建议使用def定义普通函数,不要使用lambda函数这种形式。

二.代码复用与函数递归

1.代码复用与模块化设计

我们可以把编写的代码当做一种资源,并且对这种资源进一步抽象,实现代码的资源化和抽象化。代码资源化指的是程序代码本身也是一种表达计算的资源,代码抽象化指的是使用函数等方法对代码赋予更高级别的定义。对同一份代码在需要时被重复使用就构成了代码复用,而代码复用是需要将代码进行抽象才能达到的效果。

在不同的程序设计语言中,都有代码复用的相关功能。一般来说,我们使用函数和对象这两种方法来实现代码复用。可以认为这两种方法是实现代码复用的方法,也可以认为这两种方法是对代码进行抽象的不同级别。函数能够命名一段代码,在代码层面建立初步抽象,但这种抽象级别比较低,因为它只是将代码变成了一个功能组。对象通过属性和方法,能够将一组变量甚至一组函数进一步进行抽象。

在代码复用的基础上,我们可以开展模块化设计。模块化设计是基于一种逻辑的设计思维,它的含义是通过封装函数或对象将程序划分为模块以及模块之间的表达。对于要实现的算法,如果设定了功能模块并且在功能模块之间建立关系,那么一个程序就能够被表达清楚。

在模块化设计的思想中,需要关注一个程序的主程序、子程序和子程序之间的关系。我们一般将子程序看做模块,主程序看做模块与模块之间的关系。可以认为模块化设计是一种分而治之、分层抽象、体系化的设计思想。

模块化设计有两个基本概念:紧耦合和松耦合。紧耦合是指两个部分之间交流很多,无法独立存在,那么这两个部分就是紧耦合;松耦合指的是两个部分之间交流很少,它们之间有非常清晰简单的接口,可以独立存在,这就是松耦合。

一般编写程序时,通过函数来将一段代码与代码的其他部分分开,那么函数的输入参数和返回值就是这段函数与其他代码之间的交流通道,这样的交流通道越少越清晰,那么定义的函数复用可能性就越高。所以在模块化设计过程中,对于模块内部,也就是函数内部,近可能的紧耦合,它们之间通过局部变量可以进行大量的数据传输。但是在模块之间,也就是函数与函数之间要尽可能减少它们的传递参数和返回值,让它们之间以松耦合的形式进行组织,这样每一个函数才有可能被更多的函数调用,它的代码才能更多的被复用。

2.函数递归的理解

在函数定义中,调用函数自身的方式就是递归。递归并不是程序设计的专有名词,在数学中也广泛存在,例如:n!。在n!中,我们定义当n=0时,n!为1;除此之外,其余n!=n*(n-1)!这就是一种递归形式。

在递归的定义中有两个关键的特性:链条和基例。链条指的是在递归定义中,它的计算过程是存在一种递归有序的链条关系,例如:n!=n*(n-1)!,那么n!与(n-1)!就构成了递归链条。基例指的是存在一个或多个不需要再次递归的实例,例如:当n=0时,定义n!的值为1,这就是一种基例,它与其它的值之间不存在递归关系,它已是递归的最末端。这两种关键特性就构成了递归的定义,缺少任意一个都构不成递归。在数学中被成为数学归纳法,递归也可以认为是数学归纳法思维在编程中的一种体现。

3.函数递归的调用过程

这里直接通过一个例子n!来看函数递归的调用过程,如下:

def fact(n):
    if n==0:
        return 1
    else:
        return n*fact(n-1)

可以看到要实现递归需要利用函数与分支语句进行组合。首先递归本身就是一个函数,因为它需要调用自身,如果不通过函数来定义,那么很难调用自身。接着在函数内部,需要区分基例和链条,所以要使用一个分支语句对输入参数进行判断,如果输入参数是基例的参数条件,我们就要给出基例的代码,如果不是基例的参数条件,我们要用链条的方式表达这种递归关系。

当调用fact(n)函数时,需要给出一个参数,例如n=5。当n=5时,会返回nfact(n-1),也就是5fact(4)。fact(4)又调用了函数fact(n),返回4*fact(3)。依次往下,知道调用到fact(0),满足基例,返回1。之后再依次回推,直到得到最终答案。

在这里插入图片描述
计算机调用函数会开辟内存,将函数内容复制进来,代入参数进行运算。递归看起来是调用了同一个函数,但在计算机内存中并不一样,会不停的开辟内存、复制函数、代入参数运算。

4.函数递归实例解析

实例1:字符串反转。将字符串反转后输出

#Python小白学习交流群:725638078
def rvs(n):
    if s=="":
        return s
    else:
        return rvs(s[1:])+s[0]

实例2:斐波那契数列。当n=1或2时,F(n)=1;当n>2,且为整数时,F(n)=F(n-1)+F(n-2)。

def F(n):
    if s==1 or s==2:
        return 1
    else:
        return F(n-1)+F(n-2)

实例3:汉诺塔问题

count=0
def hanoi(n,src,dst,mid):
    global count
    if n==1:
        print("{}:{}->{}".format(1,src,dst))
        count+=1
    else:
        hanoi(n-1,src,mid,dst)
        print("{}:{}->{}".format(n,src,dst))
        count+=1
        hanoi(n-1,mid,dst,src)
hanoi(3,"A","B","C")
print(count)
#数据结果为
1:A->B
2:A->C
1:B->C
3:A->B
1:C->A
2:C->B
1:A->B
7

原文链接:https://www.cnblogs.com/xxpythonxx/p/17340952.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python函数与码复用 - Python技术站

(0)
上一篇 2023年4月22日
下一篇 2023年4月22日

相关文章

  • 实践Python的爬虫框架Scrapy来抓取豆瓣电影TOP250

    标题:使用Scrapy爬取豆瓣电影TOP250 介绍 在本文中,我们将使用Python的爬虫框架Scrapy来抓取豆瓣电影TOP250的信息。Scrapy是一个高效且易于使用的Web爬虫框架,可以帮助我们快速地从网络上抓取所需要的信息。 步骤 创建一个Scrapy项目 在命令行中输入以下命令,创建一个Scrapy项目: scrapy startproject…

    python 2023年5月14日
    00
  • Python爬虫获取国外大桥排行榜数据清单

    以下是Python爬虫获取国外大桥排行榜数据清单的完整攻略。 1. 网站选择 首先,我们需要选择一个能够提供国外大桥排行榜数据的网站。通常这类网站会提供各种排名榜单,如世界最高建筑、全球最长铁路等。这里以“worldstadiums.com”为例,该网站提供了全球各国的桥梁排行榜。 2. 确定目标 通过观察网页源代码,我们可以发现排行榜的内容都保存在一个HT…

    python 2023年6月7日
    00
  • python 获取键盘输入,同时有超时的功能示例

    这里是关于如何实现Python中获取键盘输入并同时设置超时的攻略。 问题描述 在编写Python程序时,有时需要获取用户的键盘输入,但又不希望程序一直等待用户输入,这时就需要设置超时功能。下面我们将介绍如何使用Python实现获取键盘输入并实现超时的功能。 解决方案 Python中可以使用input()函数获取键盘输入,但该函数是一个阻塞式函数,即当用户输入…

    python 2023年6月2日
    00
  • python函数实例万花筒实现过程

    下面我将详细讲解 “Python函数实例万花筒” 的实现过程。 什么是 “Python函数实例万花筒” “Python函数实例万花筒” 是一种通过函数实现不同效果的代码组合。该技巧可以更好地组织代码,并避免相似功能代码的重复编写。通过改变函数的参数、输入、输出等,可以让该技巧适用于更多的应用场景。 实现步骤 步骤 1:定义函数 首先需要定义不同的函数,这些函…

    python 2023年5月19日
    00
  • Python简单爬虫导出CSV文件的实例讲解

    首先我们需要明确一下,网页爬虫是用来从互联网上抓取数据的一种程序。而CSV是一种常用的数据格式,它是一种简单的、基于文本的表格表示方法,用于表示由逗号分隔的值(即CSV文件)。 那么,如何在Python中编写一个简单的爬虫程序,并将爬取到的数据导出为CSV文件呢?下面我会详细介绍。 一、准备工作 在开始编写爬虫程序之前,我们需要安装一些必要的Python库,…

    python 2023年6月3日
    00
  • python如何去除异常值和缺失值的插值

    对于Python中的异常值和缺失值处理,通常使用的技术是插值(interpolation)。插值的原理是在已知的数据点之间构建一个函数,并使用该函数来估算未知的值。Python中常用的插值函数包括线性插值、样条插值等。 下面以前者举例说明如何使用插值去除异常值和缺失值。 去除异常值 异常值指的是在数据中出现的非自然出现的极端值,通常是由于测量误差、数据录入错…

    python 2023年5月13日
    00
  • 如何利用python实现列表嵌套字典取值

    实现列表嵌套字典取值,通常可以通过两种方式:嵌套循环取值或使用Python库中的工具。 嵌套循环取值 使用嵌套循环取值的方法会比较繁琐,但是在没有Python第三方库支持时,该方法便十分有用。 首先需要明确列表嵌套字典的数据结构,例如以下例子: data = [ {"name": "张三", "age&quo…

    python 2023年5月13日
    00
  • python检测服务器是否正常

    为了检测服务器是否正常,可以使用Python的requests库来实现。从以下几个方面来讲解这个完整攻略: 安装requests: 在使用Python的requests之前,需要先安装它。可以通过以下命令来安装: pip install requests 发送HTTP请求: 使用requests库可以通过发送HTTP请求来检测服务器是否正常。常用的HTTP请…

    python 2023年6月2日
    00
合作推广
合作推广
分享本页
返回顶部