函数和代码复用

函数是一段具有特定功能的、可重用的语句组, 通过函数名来表示和调用。经过定义, 一组语句等价于一个函数, 在需要使用这组语句的地方, 直接调用函数名称即可。

因此,函数的使用包括两部分:函数的定义和函数的使用

使用函数主要有两个目的:降低编程难度和增加代码复用。函数是一种功能抽象, 利用它可以将一个复杂的大问题分解成一系列简单的小问题, 采用分而治之的思想, 为每个小问题编写程序, 通过函数封装,当各个小问题都解决了, 大问题也就迎刃而解。

函数可以在一个程序的多个位置使用,也可以用于多个程序,当需要修改代码时, 只需要在函数中修改一次, 所有调用位置的功能都更新了, 这种代码复用降低了代码行数和代码维护难度。

函数的定义

Python语言通过保留字def定义函数

1
2
3
def <函数名> (<参数列表>) :
<函数体>
return <返回值列表>

函数名可以是任何有效的 Python标识符, 参数列表是调用该函数时传递给它的值, 可以有零个、一个或多个, 当传递多个参数时各参数由逗号分隔, 当没有参数时也要保留圆括号。

参数列表中的参数是形式参数, 简称为“形参”, 相当于实际参数的一种符号表示或符号占位符。

函数体是函数每次被调用时执行的代码, 由一行或多行语句组成。如果需要返回值, 使用保留字return和返回值列表。函数可以没有 return语句, 函数体结束后会将控制权返回给调用者。

1
2
3
4
5
6
#定义整数n的阶乘计算函数、
def fact(n):
s = 1
for i in range(1,n+1):
s *= i
return s

函数的使用

函数的定义也叫函数“声明”, 定义后的函数不能直接运行, 需要经过“调用”才能得到运行

1
<函数名> (<实际赋值参数列表>)
1
2
3
4
5
6
7
8
9
#定义整数n的阶乘计算函数、
def fact(n):
s = 1
for i in range(1,n+1):
s *= i
return s
#用户输入,并调用函数打印输出
n = eval(input("输入一个整数计算阶乘:"))
print(fact(n))

函数的四个步骤:

  1. 函数定义:使用def保留字将一段代码定义为函数, 需要确定函数名、参数名、参数的个数, 使用参数名称作为形式参数(占位符)编写函数内部的功能代码。
  2. 函数调用:通过函数名调用函数功能,对函数的各个参数赋予实际值, 实际值可以是实际数据, 也可以是在调用函数前已经定义过的变量。
  3. 函数执行:函数被调用后, 使用实际参数(赋予形式参数的实际值)参与函数内部代码的运行,如果有结果则进行输出。
  4. 函数返回:函数执行结束后, 根据 return保留字的指示决定是否返回结果, 如果返回结果, 则结果将被放置到函数被调用的位置, 函数使用完毕, 程序继续运行。

编程中大量使用函数已经成为一种编程范式, 叫作函数式编程。函数式编程的主要思想是把程序过程尽量写成一系列函数调用, 这能够使代码编写更简洁、更易于理解, 是中小规模软件项目中最常用的编程方式。

注意:函数也是有类型的,以上面的阶乘计算函数为例

1
print(type(fact))		#<class 'function'>

Python还有一种最小函数,不表达任何功能

1
2
def f():
pass

其中, 保留字pass表示不进行任何操作, 起到占位的作用, 因为函数体内部总要编写一行代码, pass用来表示这种占位。对f()的调用不实现任何功能。

函数的参数传递

可选参数传递

函数的参数在定义时可以指定默认值, 当函数被调用时, 如果没有传入对应的参数值, 则使用函数定义时的默认值替代。

1
2
3
def <函数名> (<非可选参数列表>,<可选参数> = <默认值>)
<函数体>
return <返回值列表>

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

1
2
3
4
5
#两数相乘函数
def cheng(x,y = 10):
print(x*y)
cheng(10) #100
cheng(10,5) #50

参数名称触地

函数调用时,默认采用按照位置顺序的方式传递给函数,Python语言同时支持函数按照参数名称方式传递参数,

1
<函数名> (<参数名> = <实际值>)

采用参数名称传递方式不需要保持参数传递的顺序, 参数之间的顺序可以任意调整, 只需要对每个必要参数赋予实际值即可, 这种方式会显著增强程序的可读性。

1
2
3
4
5
#两数相乘函数
def cheng(x,y = 10):
print(x*y)
cheng(x=10) #100
cheng(x=10,y=5) #50

函数返回值

return语句用来结束函数并将程序返回到函数被调用的位置继续执行。

return语句可以出现在函数中的任何部分, 同时可以将0个、1个或多个函数运算的结果返回给函数被调用处的变量

1
2
3
def cheng(x,y = 10):
return x*y
print(cheng(10)) #100

函数可以没有 return, 此时函数并不返回值。当函数使用 return返回多个值时,可以使用个变量或多个变量保存结果。

1
2
3
def cheng(x,y = 10):    
return x*y,x+y
print(cheng(10)) #(100, 20)

变量作用域

根据程序中变量所在的位置和作用范围, 变量分为局部变量和全局变量。

局部变量仅在函数内部使用, 且作用域也在函数内部。

全局变量可以跨越函数使用, 作用域覆盖整个程序。

局部变量

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

1
2
3
4
5
6
def cheng(x,y = 10):    
z = x * y
return z
s = cheng(10)
print(s) #100
print(z) #报错

cheng函数调用后,变量z将不存在,因此再使用这个变量会报错。

全局变量

全局变量指在函数之外定义的变量, 在程序执行全过程有效。

全局变量在函数内部使用时需要提前使用保留字global声明

1
global <全局变量>
1
2
3
4
5
6
7
z = 2
def cheng(x,y = 10):
global z
return x * y * z
s = cheng(10)
print(s) #100
print(z) #2

如果未使用保留字global声明, 即使名称相同, 也不是全局变量

1
2
3
4
5
6
7
z = 2
def cheng(x,y = 10):
z = x * y
return z
s = cheng(10)
print(s) #100
print(z) #2

代码复用

函数是程序的一种基本抽象方式, 它将一系列代码组织起来通过命名供其他程序使用。

函数封装的直接好处是代码复用, 任何其他代码只要输入参数即可调用函数, 从而避免相同功能代码在被调用处重复编写。代码复用有另一个好处, 当更新函数功能时, 所有被调用处的功能都被更新。

程序由一系列代码组成, 如果代码是顺序但无组织的, 不仅不利于阅读和理解, 也很难进行升级和维护。当程序长度在百行以上, 如果不划分模块, 程序的可读性就已经很糟糕了。

解决这问题最好的方法是将一个程序分割成短小的程序段, 每一段程序完成一个小的且特定的功能。利用函数将程序合理划分为多个功能模块, 并基于模块设计程序是一种常用的程序设计方法, 被称为“模块化设计”。

模块化设计指通过函数的封装功能将程序划分成主程序、子程序和子程序间关系的表达。

模块化设计是使用函数设计程序的思考方法,以功能块为基本单位,一般有两个基本要求:

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

耦合性指程序结构中各模块之间相互关联的程度, 它取决于各模块间接口的复杂程度和调用方式。

耦合性是影响软件复杂程度和设计质量的一个重要因素。

紧耦合指模块或系统间关系紧密,存在较多或复杂的相互调用。

紧耦合的缺点在于更新一个模块可能导致其他模块变化,复用较困难。

松耦合一般基于消息或协议实现,系统间交互简单。

函数递归

函数是一种代码封装, 能够被其他程序调用, 当然, 也可以被函数自身的内部代码调用。

这种函数定义中调用函数自身的方式称为递归。

递归在数学和计算机应用上非常强大,能够非常简洁地解决重要问题

递归的关键特征:

  • 递归基例:存在一个或多个基例,不需要再次递归,它是确定的表达式。
  • 递归链条:所有递归都有一个链条,表现为函数功能的不同值调用。
1
2
3
4
5
6
7
8
#递归计算阶乘函数
def fact(n):
if n == 0:
return 1 #0的阶乘是1
else:
return n*fact(n-1)
n = eval(input("请输入一个整数计算阶乘:"))
print(fact(n))

每次函数调用时, 函数参数的副本会临时存储,递归中各函数再运算自己的参数, 相互没有影响。当基例结束运算并返回值时, 各函数逐层结柬运算,向调用者返回计算结果。

1
2
3
4
5
6
7
8
#递归反转字符串
def reverse(s):
if s == "":
return s
else:
return reverse(s[1:])+s[0]
s = input("请输入一个字符串:")
print(reverse(s))

过程式与函数式编程

编程方法是如何思考、设计、编写程序的方法, 与编程语言的语法一样重要。

过程式编程是一种以计算过程或运算流程为中心的编程方法, 也是一种十分自然、符合人类思维方式的编程方法。

面对一个计算任务, 最直接的描述方式是按照操作流程或步骤进行分解并编写代码逐步实现流程或步骤所要求的计算功能。

过程式编程采用这种方式, 以划分计算步骤为主要方法, 组织程序代码。Python语言通过编程语句支持过程式编程。一般来说,采用顺序、分支、循环等逻辑就可以完整描述计算过程。

函数式编程方法是过程式编程的一种演进, 亦称模块式编程。

函数式编程的主要思想是把程序过程尽量写成一系列函数调用, 这能够使代码编写更简洁、更易于理解。函数式编程是软件项目中最常用的编程方式,也是代码复用的主要方式

Python实例

软文诗词风

将软文的正常排版方式变为短句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#软文诗词化
txt='''
临江仙·滚滚长江东逝水
明·杨慎

滚滚长江东逝水,浪花淘尽英雄。是非成败转头空。青山依旧在,几度夕阳红。
白发渔樵江渚上,惯看秋月春风。一壶浊酒喜相逢。古今多少事,都付笑谈中。
'''

linewidth = 20 #预定的输出宽度
#分割软文
def lineSplit(line):
#辨识所有可能出现的符号
List = [',','.','!','?',',','。','!','?']
for p in List:
#把符号换成换行
line = line.replace(p,'\n')
#通过换行来分割文章
return line.split('\n')
#注意这时如果直接输出,会是一个列表
#设置排版
def linePrint (line):
#获取全局变量-输出宽度
global linewidth
#居中显示,chr(12288)表示中文空格,用于居中填充
print(line.center(linewidth,chr(12288)))

newlines = lineSplit(txt)
for line in newlines:
linePrint(line)