河南师范大学python+学习笔记5 函数和代码复用

吃水不忘挖井人
首先对河南师范大学的各位老师们说声谢谢。他们是:
张磊老师、张倩倩老师、刘金金老师、郭凌云老师、李晓艳老师、李志先老师、陶华亭老师、周雪燕老师、王爱菊老师、陈劲松老师、黄晓巧老师、夏辉丽老师

第五章 函数和代码复用

5.1 函数的基本使用

5.1.1 函数的定义
函数是一种功能抽象, 是一段具有特定功能的、可重用的语句组,用函数名来表示并通过函数名完成功能调用。

函数也可以看作是一段具有名字的子程序,可以在需要的地方调用执行,
不需要在每个执行地方重复编写这些语句。每次使用函数可以提供不同的参数作为输入,以实现对不同数据的处理。
函数执行后,还可以反馈相应的处理结果。

基本的Python内置函数 Python解释器提供了68个内置函数(下面介绍32个)

用户自定义函数。
 函数在调用前必须先定义。

Python使用def保留字定义一个函数,
语法形式如下:
def <函数名>(<参数列表>):
<函数体>
return <返回值列表>

 函数名可以是任何有效的Python标识符。
 参数列表是调用该函数时传递给它的值,可以有零 个、一个或多个,当传递多个参数时各参数之间由 逗号分隔,当没有参数时也要保留圆括号。
 定义函数时,函数名后面参数列表中的变量是形式 参数,简称“形参”。形参只在函数内部有效。
 调用函数时,函数名后面小括号中提供的值或者变 量是实际参数,简称“实参”。实参可以是常量、 变量、表达式或者函数。
 函数体由一个或多个语句组成,是函数被调用时执 行的代码。
 return语句的作用是结束函数调用,并将结果返回 给调用者。return语句是可选的,可以出现在函数 体的任意位置。若无return语句,函数体结束后会 将控制权返回给调用者。
实例5.1:生日歌。

过生日时要为朋友唱生日歌,歌词为:

 Happy birthday to you!
 Happy birthday to you!
 Happy birthday, dear <名字>
 Happy birthday to you!

编写程序为Mike和Lily输出生日歌。

最简单的实现方法是重复使用print()语句,如下:

扫描二维码关注公众号,回复: 11756381 查看本文章
	print("Happy birthday to you!")
	print("Happy birthday to you!") 
	print("Happy birthday, dear Mike!") 
	print("Happy birthday to you!")


def happy():
 print("Happy birthday to you!")

5.1.2 函数的调用过程

函数的定义也叫函数的“声明”,定义后 的函数不能直接运行,
需要经过“调用”才能 运行。
调用函数的基本方法如下:
<函数名>(<实际赋值参数列表>)

实例5.1 HappyBirthday.py

def happy():
 print("Happy birthday to you!") 
def happyB(name):
 happy()
 happy()
 print("Happy birthday, dear {}!".format(name))
 happy() 
happyB("Mike")
print() 
happyB("Lily")

>>>
 Happy birthday to you!
 Happy birthday to you!
 Happy birthday, dear Mike!
 Happy birthday to you!

 Happy birthday to you!
 Happy birthday to you!
 Happy birthday, dear Lily!
 Happy birthday to you!

程序调用一个函数需要执行以下四个步骤:
(1)调用程序在调用处暂停执行;
(2)在调用时将实参赋值给函数的形参;
(3)执行函数体语句;
(4)函数调用结束给出返回值,程序回到调用 前的暂停处继续执行。

5.1.3 lambda函数

lambda表达式可以用来声明匿名函数,又称 lambda函数。
匿名函数并非真的没有名字,而是 将函数名作为函数结果返回,
使用形式如下:
<函数名> = lambda <参数列表>: <表达式>
 lambda函数与正常函数一样,等价于下面形式:
def <函数名>(<参数列表>):
return <表达式>

简单说,lambda函数用于定义简单的、能 够在一行内表示的函数,返回一个函数类型,
实例如下:

>>>f = lambda x, y : x + y 
>>>type(f) 
<class 'function'> 
>>>f(10, 12) 22 
>>>type(f(10, 12)) 
<class ‘int'> 

还可以将lambda表达式作为列表的元素, 从而实现跳转表的功能,也就是函数的列表。
 Lambda表达式列表的定义方法如下:
列表名=[(lambda表达式1),(lambda表达式2),…]
 调用列表中lambda表达式的方法如下:
列表名 [索引](lambda表达式的参数列表)

例如:
m=[(lambda x: x2),( lambda x: x3),( lambda x: x**4)] print(m0,m1,m2)
输出结果为:4 8 16

5.2 函数的参数传递

5.2.1 可选参数传递
函数的参数在定义时可以指定默认值,当函数 被调用时,如果没有传入对应的参数值,则使用函 数定义时的默认值替代,
语法形式如下:
def <函数名>(<非可选参数列表>, <可选参数> = <默认值>):
<函数体>
return <返回值列表>

需要注意,可选参数一般都放置在非可选参数 的后面,即定义函数时,
先给出所有非可选参数, 然后再分别列出每个可选参数及对应的默认值。

>>>def func(x, y = 10):
         print(x*y) 
>>>func(99)
 990 
>>>func(99, 2)
 198 

5.2.2 参数的位置和名称传递
函数调用时,实参默认采用按照位置顺序的方 式传递给形参,但当参数很多时,这种调用函数的 方式可读性较差。
例如:func()函数有6个参数, 分别表示两组三维坐标值。
func (x1,y1,z1,x2,y2,z2);
return
它的一个实际调用如下:result=func(1,2,3,4,5,6)

如果仅看实际调用丌看函数定义,很难理解这 些参数的含义。
另外在规模大的程序中,函数定义可能在函数库中,也可能不调用相距很远,可读性较差。
为了解决上述问题,Python提供了按照形参 名称输入实参的方式,
调用如下: result=func(x2=4,y2=5,z2=6,x1=1,y1=2,z1=3)
由于调用函数时指定了参数名称,所以参数之 间的顺序可以任意调整。

5.2.3 函数的返回值
return语句用来退出函数并将程序返回到函数 被调用的位置继续执行。

函数可以没有return语句,此时函数并丌返回 值,如实例5.1的happy()函数。

return语句同时可以将0个、1个或多个函数运 算完的结果返回给函数被调用处的变量,返回 多个值时以元组类型保存。
例如:
>>>def func(a, b):
return b,a
>>>s = func(“knock~”, 2)
>>>print(s, type(s))
(2, ‘knock~’) <class ‘tuple’>

5.3 变量的作用域

根据程序中变量所在的位置和作用范围, 变量分为局部变量和全局变量。
局部变量仅在函数内部,且作用域也在函数内部,全局变量的作用域跨越多个函数。

5.3.1 局部变量
局部变量指在函数内部使用的变量,仅在函数内部有效,当函数退出时变量将不再存在。

>>>def func(x, y = 10):
         z = x*y    # z是函数内部的局部变量
         return z 
>>>s = func(99, 2) 
>>>print(s) 198 
>>>print(z) 
Traceback (most recent call last):
   File "<pyshell#11>", line 1, in <module>
     print(z) 
NameError: name 'z' is not defined 
    变量z是函数func()内部使用的变量,当函数调用后,变量z将不存在。 

5.3.2 全局变量
全局变量指在函数之外定义的变量,在程序执行全过程有效。
全局变量在函数内部使用时,需要 提前使用global保留字进行声明,
语法形式如下:
global <全局变量>

>>>n = 1    #n是全局变量 
>>>def func(a, b):        
 	c = a * b   #c是局部变量,a和b作为函数参数也是局部变量 
        return c 
>>>s = func("knock~", 2) 
>>>print(c) 
Traceback (most recent call last):
   File "<pyshell#6>", line 1, in <module>
     print(c)
 NameError: name 'c' is not defined 

这个例子说明,当函数执行完退出后,其内部变量将被释放。

>>>n = 1    #n是全局变量 
>>>def func(a, b): 
        n = b  #n是函数内存中新生成的局部变量,不是全局变量
        return a*b 
>>>s = func("knock~", 2) 
>>>print(s, n)  #测试一下n值是否改变 
knock~knock~ 1 

函数func()内部使用了变量n,并且将参数b赋值给变量 n,
为何全局变量n值没有改变?如果未使用保留字global声 明,即使名称相同,也不是全局变量。

如果希望让func()函数将n当作全局变量,需要在变量n 使用前显式声明该变量为全局变量,
代码如下

>>>n = 1    #n是全局变量 
>>>def func(a, b): 
        global n 
        n = b    #将局部变量b赋值给全局变量n  
        return a*b 
>>>s = func("knock~", 2) 
>>>print(s, n)  #测试一下n值是否改变
knock~knock~ 2 

代码复用和模块化设计
函数是程序的一种基本抽象方式,它将一系列代码组织起来,通过命名供其他程序使用。
函数封装的直接好处是代码复用,任何其他代码叧要输入参数即可调用函数,从而避免相同功能代码在被调用处重复编写。
代码复用产生了另一个好处,当更新函数功能时,所有被调用处的功能 都将被更新。

当程序的长度在百行以上,如果丌划分模块就算是最好的程序员也很难理解程序含义,
程序的可读性就会非常糟糕。解决这一问题的最好方法是将一个程序分割成短小的程序段,
每一段程序完成一 个小的功能。无论面向过程和面向对象编程,
对程序合理划分功能模块并基于模块设计程序是一种常用方法,被称为“模块化设计”。

模块化设计一般有两个基本要求:

紧耦合:尽可能合理划分功能块,功能块内部耦合 紧密; 
松耦合:模块间关系尽可能简单,功能块之间耦合 度低。

使用函数叧是模块化设计的必要非充分条件,根据计算需求合理划分函数十分重要
一般来说,完成特定 功能或被经常复用的一组语句应该采用函数来封装,并尽可能减少函数间参数和返回值的数量。

5.5 函数的递归

5.5.1 递归的定义
函数作为一种代码封装,可以被其他程序调用,当然,也可以被函数内部代码调用。
这种函数定义中调用函数自身的方式称为递归。 就像一个人站在装满镜子的房间中,看到的影 像就是递归的结果。
递归在数学和计算机应用 上非常强大,能够非常简洁的解决重要问题。

数学上有个经典的递归例子叫阶乘,
阶乘通常定义为:
n!=n(n-1)(n-2)…(1)

这个关系给出了另一种表达阶乘的方式:

阶乘的例子揭示了递归的2个关键特征:
(1)存在一个或多个基例,基例丌需要再次递归,它是确定的表达式;
(2)所有递归链要以一个或多个基例结尾。

5.5.2 递归的使用方法

实例5.2:阶乘的计算。
根据用户输入的整数n,计算并输出n的阶乘值。

实例5.2 5.2CalFactorial.py

def fact(n): 
    if n == 0: 
        return 1     
    else: 
        return n * fact(n-1) 
num = eval(input("请输入一个整数: ")) 
print(fact(abs(int(num))))   

实例5.3:字符串反转。
对于用户输入的字符串s,输出反转后的字符串。
解决这个问题的基本思路是把字符串看作一个递归对象。

def reverse(s): return reverse(s[1:]) + s[0]

观察这个函数的工作过程。s[0]是首字符,s[1:] 是剩余字符串,将它们反向连接,可以得到反转字符 串。执行这个程序,
结果如下:

>>>def reverse(s): return reverse(s[1:]) + s[0] 
>>> reverse("ABC") 
... RecursionError: maximum recursion depth exceeded 

reverse()函数没有基例,递归层数超过了系统允许的最大递归深度。

默认情况下当递归调用到1000层,python 解释器将终止程序。递归深度是为了防止无限递 归错误而设计的,当用户编写的正确递归程序需 要超过1000层时,可以通过如下代码设定。

>>>import sys 
>>>sys.setrecursionlimit(2000)  #2000是新的递归层数 

def reverse(s):
     if s==“”: 
       return s 
     else:
       return reverse(s[1:]) + s[0] 
str=input(“请输入一个字符串:”) 
print(reverse(str) ) 

此例中把基例设置为字符串的最短形式,即空字符串。

猜你喜欢

转载自blog.csdn.net/qq_41952762/article/details/103144551