三.函数
在我们编写代码的过程中,通常会发现代码的某些操作是重复使用的,这让我们在编写代码的时候常常采取复制粘贴的模式,然而这样的模式似乎显得有些麻烦,对于学习编程的人来说会比较low,工作效率也比较低,由此,我们引入了函数和模块的概念。
函数的作用
提出什么样的问题,就要去找到对应的解决方案,要想写出高质量的代码首先要解决的就是代码重复的问题,而函数的功能就是将具有特定功能的代码块封装起来,以便于后期写代码时调用该函数来执行相应的功能,这样就减少了代码重复的可能,并且让代码看起来更加的优美
函数定义
python中的函数与数学上的一致,每个函数都有函数名,自变量和因变量,但在python中我们称自变量为函数的参数,因变量称为返回值。
在Python中,我们用关键字def来定义函数,其后接函数名,函数名后必须跟一个圆括号,括号内用来装传入的参数,最末以冒号结尾,具体示例如下:
def function_name(parameters:参数类型)->返回类型:
#注意:一般在编写函数的时候,我们会指定函数参数类型以及返回值类型,这样做的目的是增强代码的可读性
传入的参数可以没有,也可以是多个,多个参数之间用逗号隔开,并且可以指定参数的默认值。
通常情况下,我们传入的都是位置参数,在调用函数时,只需要在对应位置上传入实参即可,但在某些时候,我们希望在调用函数时调用者必须以参数名=参数值的方式传参,就需要用到 ‘*’将位置参数与命名关键字参数隔开,” * “前为位置参数,” * “ 后为命名关键字参数,实例代码如下:
该函数的作用是给定一个文件名,找到该文件名的后缀名,若无后缀名,则返回空值,其中,传入的参数是文件名的字符串,‘ * '后面指定是否输出带点的后缀名
def get_suffix(filename:str,*,has_dot)->str:
position=filename.rfind('.')
if position <= 0:
return ' '
if not has_dot:
position+=1
return filename[position:]
print(get_suffix('sdf.ef',has_dot=True)) # .ef
#在这个代码中,如果函数中没有指定has_hot的默认值,在调用该函数时,如果传入参数不是带关键字参数名=参数值的形式,则会报错
需要知道的是,在设计函数时,如果函数的参数个数暂时无法确定,我们可以使用可变参数*args来接收任意数量的位置参数,**keargs用来接受任意数量的关键字参数,其本质是一个字典,字典的键对应的关键字名,值对应关键字的值,如下:
def add(*args,**keargs):
示例代码:
def calculate(*args,init_value,**kwargs):
"""
:param fn:
:param args:
:param kwards:
:return:
"""
total=init_value
for arg in args:
if type(arg) in (int,float):
total+=arg
for value in kwargs.values():
if type(value) in (int, float):
total += value
return total
print(calculate(1,2,3,4,init_value=0,x=1,y=2,z=3)) #16
#以上代码可以看出,定义了位置参数和关键字参数后,我们在调用代码时可以传入任意多的位置数和关键字参数
以上的函数,可以看到,def下有几行代码注释,这里可以解释函数的功能以及对各个参数进行说明,增加代码的可读性,方便以后的调用,在编写函数时,我们应该这样去做
当函数首行定义好之后,冒号后回车,在已经缩进格式下开始编写代码,后面的代码块均在相同的缩进下进行编写
函数主体模块编写好之后,需要有函数的返回值, 可以通过 return 来指定函数的返回值,函数的返回值可以是谋变量值,也可以是一个表达式,注意:return具有结束调用当前函数的功能,如果不加return关键字,则函数返回值是None
高阶函数
掌握基础函数概念之后,就可以进入高阶函数的概念了。函数的参数和返回值可以是任意类型的对象,这就意味着函数本身也可以作为函数的参数或返回值,这就是所谓的高阶函数。
举个例子吧
当我们在编写函数的时候,可能会对多个参数做相同的运算,此时我们就会把该运算封装成一个函数,在编写一个函数时,如果需要该方法,那我们可以直接在参数列表传入这个函数的方法,具体例子如下:
def calculate(*args,init_value,fn,**kwargs):
"""
:param fn:
:param args:
:param kwards:
:return:
"""
total=init_value
for arg in args:
if type(arg) in (int,float):
total=fn(total,arg)
for value in kwargs.values():
if type(value) in (int, float):
total = fn(total, value)
return total
编写二元函数,并调用函数:
def add(x,y):
return x+y
def mul(x,y):
return x*y
print(calculate(11,22,33,44,init_value=0,fn=add)) #110
print(calculate(1,2,3,4,init_value=1,fn=mul)) #24
匿名函数Lambda
Lambda函数:不用使用函数定义模式来定义的一个函数,只能有一行代码,代码中的表达式的运算结果就是该函数的返回值,语法模式如下:
lambda [arg1 ,arg2,.....argn]:expression
由上述编写的二元运算函数不难看出,其编写简单,只需要一条语句就能完成,因此我们可以使用Lambda函数来实现该功能,代码如下:
print(calculate(11,22,33,44,init_value=0,fn=lambda x,y:x+y)) #110
print(calculate(1,2,3,4,init_value=1,fn=lambda x,y:x*y)) #24
不难看出,由lambda实现的函数与上述例子想相同,并且,编写的代码相对简单灵活
函数递归调用
在编写函数时,函数可以调用别的函数,也可以调用自己,函数如果直接或间接的调用自己,我们称之为递归调用,递归函数两个要点是:递归公式和递归体,,示例如下:
def fac(num: int) -> int:
if num == 0:
return 1
return num * fac(num - 1)
if __name__ == '__main__':
print(fac(5)) #120
说到这里,函数的基本概念已经基本讲完,此时我们会思考一个问题,当我们调用的函数不在同一个文件下就无法成功调用函数,下面我们就来解决这个问题
导入模块
模块是一个包含所有你定义的函数和变量的文件,后缀名是 .py 。想要在别的源文件中使用该文件里的函数模块,就必须执行 import 语句导入该函数模块
#import 模块
#导入random模块
import random
from…import 语句:是让你从某个模块导入指定的部分到当前的源文件
from modname import name1,name2,name3...nameN
以上就是导入模块的方式
总结:在编写代码的时候,我们应该注意重复代码以及关注代码的复用性,学会提取重复代码并重构函数,拥有函数和模块的概念。在编写代码的时候,注意一些细节上的问题,学会使用Lambda函数简化代码步骤