大家好,大家有没有意识到,自从上节课我们学习了程序流程控制语句,我们将解决问题的能力提升了一个数量级,从点的范畴,拓展到了线(甚至可以是无数条线)的领域,实际上拥有了这些技能,我们已经可以编写完整的Python程序了。
但是,我们再仔细观察一下,我们依靠现有的语法工具(常量、变量、运算符、表达式、流程控制语句等),基本上只能提供一些基于线性的解决方案。也就是说,我们实现代码所能运用的语法工具无外乎流程控制语句所能驾驭的范畴,代码所处理的对象的最大粒度还是“变量”。无论你写多少行代码,都只能是自上而下的按照或者判断,或者分支,或者循环,或者运算的过程处理所有需要处理的各种变量,来完成待处理的任何事务逻辑。因此,我们所有的代码处理流程都还局限在一维的线性空间里。
如果我们的工具不能突破一维的局限,认知就不能上升到一个新的维度,也就无法看到一个新的世界。
在实际的应用程序开发中,我们面临的往往就是错综发杂的应用需求,那么,Python是否有更加高效的语言工具呢?答案是:有的!这就是我们今天要学习的函数。
简单的说,函数就是一个被命名的代码块。
它看起来没什么新意,不过是给代码块加上了一个名字。没错,它的意义肯定不在于它的名字有多么动听,而是因为:
1、这样的代码块,允许包含任何可执行的代码。
2、可重复不限量地被使用。
有没有想过,这实际上意味着什么?
它意味着,因为函数的引入,让你的应用程序拓展了一个新的维度。你曾经编写的任何有用的代码,无论它有多大的规模或者功能多么强大(虽然通常都是有限的),它都可以被封装到一个函数里,而这个函数又将构成一个新的应用流程的一个部分,而且它还可以反复被调用。函数作为一个新的对象,就像之前的变量一样,它将构成你的程序代码的新的组成部分,它让你的代码所处理的对象的最大粒度一下子从一个点(常量或变量),变成了一个面(函数代码块)。你的代码效率和可重用性立即得到质的飞跃。
所以,千万不要小看函数的概念。
PS:这里包含了一个程序员一定要有的代码复用的思想。表面上看,它只是减少了程序员的劳动量,提高了编程效率。而本质上,它将应用程序解决问题的能力扩展到了一个新的维度,从一维的线性处理流程,扩展到了二维、甚至更高的维度。也许上面这一段文本,你需要真正编写一些时日的代码你才能真正领悟到它的意义和思想精髓,但是,没有关系,当下能引起你的重视就足够了。
1、函数的定义
(1)、使用 def 关键字。
(2)、在关键字的后面,创建一个函数的名称(标识符)。
(3)、函数名称的后面,再跟一对圆括号,其中可以包括一些变量名(参数)。
(4)、最后再以冒号结束这一行。
(5)、其实,函数并没有结束。真正的函数主体在后面,必须另起一行,并缩进书写该函数的代码块。代码块所能实现的功能,决定了函数存在的意义。
# 示例( function_1.py )
def say_hello():
# 该块属于这一函数
print('hello world')
# 函数结束
say_hello() # 调用函数
say_hello() # 再次调用函数
说明:请注意,我们可以两次调用相同的函数,这意味着我们不必重新把代码再写一次。
PS:有其他语言经验的同学可能已经发现了,Python的函数定义方法,相比C/C++或这Java、C#的函数(或方法),正如流程控制语句的定义一样,要简洁很多。
2、函数的参数
函数概念可能是在任何复杂的软件(无论使用的是何种编程语言)中最重要的部分,所以我们接下来将在本节中探讨有关函数的各个方面。函数的命名,作为标示符的一种,前面已经讨论过了。这里重点讲一下函数的参数问题。
在函数名后面的括号里,允许函数通过变量名获取参数。这个参数的值是由函数的调用者赋值给它的。这就在调用和被调用之间形成了一个传递变量值的通道。调用的概念,下面马上会讲到,函数因此可以利用这些值来做一些需要的事情,多个参数以逗号分隔。
请注意,这里有个术语:
(1)在定义函数时给定的参数名称,称作“形参”Parameters),
(2)在调用函数时,给函数提供有值的参数,称作“实参”(Arguments)。
PS:如果你想做一个专业的程序员,这些常用的术语最好能够脱口而出。
# 示例( function_2.py )
def print_num(a, b):
if a > b:
print(a, '是较大的数!')
elif a == b:
print(a, '等于', b)
else:
print(b, '是较小的数!')
# 调用1_传递常量值
print_num(3, 4)
# 调用2_传递参数
x = 5
y = 6
print_num(x, y)
说明:上面的示例,首先定义了一个名称为print_num的函数,并且分两次调用了这个函数。请注意,函数print_num有两个形参a和b。我们在调用这个函数时,(有值的)实参是按先后顺序来给形参传值的,也就如上面的2和x是传给a的,4和y是传给的。强调这一点很重要,因为,下面我们会讲到另一种特例参数叫“关键参数”,它不是靠顺序而是靠名称来传值的,请留意下文。
3、函数的局部变量
请注意,我们在函数中定义的变量是局部变量。也就是说,它只能在函数定义范围内有效。换言之,函数中变量的作用域就是这个函数的代码块。
x = 10
def func_3(x):
print('x is', x) #第一次打印
x = 5
print('函数内部变量x的值:', x) #第二次打印
#调用函数显示x和直接显示x的值
func_3(x)
print('函数外部变量x的值:', x) #第三次打印
说明:请注意,这个示例中在函数的外部和内部同时创建的两个名为x的变量,但他们本质上并不是同一个变量。函数内部的任何自定义变量都是函数的局部变量,仅在函数内有效。但是,即便如此,我们仍然要尽量避免这样的命名习惯,因为它非常容易让程序员搞混淆,以至于将程序弄错或者产生莫名其妙的bug。上述案例仅仅只是为了说明局部变量无法影响外部变量而设置的。
4、函数的global 语句
除了局部变量,还有一种叫全局变量的东西。它是不局限任何作用域的顶层变量。
那么,在函数的内部,如果你想给一个全局变量赋值怎么办?我们就需要通过 global 语句来完成这件事。因为在不使用 global 语句的情况下,不可能为一个定义于函数之外的变量赋值。
#示例 function_4.py
x = 10 #这是一个全局变量
def func_4():
global x#此处声明了x为全局变量
print('x 的值为:', x)
x = 5
print('改变以后的全局变量的值为:', x)
func_4()
print('再次显示x的值为:', x)
说明:
请注意,这里三次打印的结果:
(1)第一次打印,输出的是全局变量x值(10)。
(2)第二次打印,输出是被修改后的x值(5)。
(3)第三次是一个打印语句,输出的然是x的当前值(5),已被函数修改。
5、函数的默认参数
函数的参数,本质上就是变量。函数在被调用的时候,如果存在参数,参数就应该被赋值,也就是形参通过实参赋值。但是,如果调用时未给参数赋值,会发生什么呢?按照Python的变量定义规则,使用未赋值的变量,程序是会报错的。为此,对一些参数而言,你可以给它设置默认值,以避免用户调用时未提供实参而出现错误的情形。
请注意,函数的默认参数,只能位于参数列表的末尾,这个顺序是强制的。
实际上,给函数的参数设置默认值,就是给参数赋初始值。但是,请注意不要将可变对象赋值给默认参数。
6、函数的关键字参数
如果你的函数有多个参数,而你在调用时,只想对其中的一些赋值,那么你可以通过命名它们来给这些参数赋值,这就是关键字参数(Keyword Arguments)
关键参数使用命名(关键字)而非位置(如前所述一直以来我们所使用的方式)来指定函数中的参数。这样做有两大优点:
其一,我们不再需要考虑参数的顺序,函数的使用将更加容易。
其二,如果其它参数都有默认参数值,我们就可以只对那些我们希望赋值的参数赋值。
#示例 function_4.py
def func_4(a, b=5, c=10):
print('a is', a, 'and b is', b, 'and c is', c)
func_4(3,7) #调用一
func_4(25, c=24) #调用二
func_4(c=50, a=100) #调用三,
说明:
(1)函数func_4有三个形参,但其中b和c已经赋了默认值(也叫初始值)。
(2)调用一:默认按顺序赋值给a、b。
(3)调用二:第一个值按顺序赋值给a,第二个值为指定关键字赋值给c。
(4)调用三:不考虑顺序,仅对指定关键参数赋值。
请注意,在这样的有默认参数的函数调用时,无论是否指定关键参数赋值,都不能忽略函数的非默认参数,必须赋值,不能漏掉。
7、函数的 return 语句
(1)、函数的return 语句,用于从函数中返回,也就是中断函数。
(2)、使用return语句时,也可以选择在中断函数的同时,从函数中返回一个值,这个返回值能够被调用该函数的对象接收到。这也是我们会大量用到的函数的一个重要特性。
#示例 function_5.py
def func_5(x, y):
if x > y:
return x
elif x == y:
return '这两个数字是相等的!'
else:
return y
#输出
print(func_5(3, 3))
说明:函数中包含一个条件分支语句,符合任一条件,函数将终止,并返回相应的值。
8、函数的DocString
函数文档字符串documentation string (docstring)是在函数开头,用来描述函数的文档字符串。简言之,它就是该函数的帮助文档,并且可以使用help()内置函数查看该文档。更加神奇的是,还可以使用函数的__doc__属性获取该文档的内容。在一些高级的代码编辑器中,调用函数时,我们将鼠标移动到函数名称上,就会帮我们显示这个函数描述文本,给我们编写代码带来极大的便利。因此,我们应该尽可能的习惯使用函数的文档字符串。一般地,该描述文档应该包含以下信息:
1、函数的基本信息
2、函数的功能描述
3、每个形参的类型和用途
#示例 function_6.py
def func_6(x, y):
'''打印x、y中的最大数。
x、y都应该是整数'''
# 将x和y进行数据类型转换(为整数类型)
x = int(x)
y = int(y)
if x > y:
print(x, '是较大的数!')
else:
print(y, '是较大的数!')
func_6(3, 5)#调用该函数
print(func_6.__doc__)#显示(打印)该函数的描述文档
使用方法:
1、放置在函数的首行。
2、使用三引号,如''' ''',实现撰写多行文本字符串。
3、函数文档第一行一般是功能概述,第二行为空,第三行详细描述。请尽量遵守这个约定。
查看方式
1、在交互模式下可以使用help()查看函数的帮助文档。
2、使用__doc__属性查看,可以获取该函数的描述文档。
小结
这节课,我们学习了函数。不仅学习了函数定义的语法规则,更重要的是尝试了编写和使用函数的方法,虽然并没有遍历Python的所有函数类型,但是,已经足够帮助我们完成对编程认知的又一次跃迁。