首先,我们来思考三个问题:
1. 什么是函数
2. 为什么要有函数
3. 怎么用函数。
搞懂了这三个问题,我们对函数就会有一个大概的了解。
什么是函数:
函数就是具备某一功能且可以反复使用的工具。举个例子:当没有函数的时候,我们写一段登录的代码可能要十行甚至二十行,有了具备登录功能的函数,我们只需要使用就可以实现登录的功能。当过了一会儿我们又需要登录,可以再次调用登录函数进行登录。这就是具备某一功能且可以反复使用的工具——函数。
当然,并不是说我们直接就可以使用函数,在使用函数之前我们必须先定义函数,说白了就是先把具备某一功能的函数制造出来我们才能进行使用。函数的制造过程就叫做定义一个函数的过程,而遇到场景需要使用函数就是函数的调用。
为什么要有函数:
如果没有函数,我们写的代码会有很多重复的地方。还拿登录来举例,你写完登录过程,过了100行左右,又要写一遍登录,不用函数的话就只能从上面copy下来,造成诸多问题:代码冗余,可读性差,可扩展性差。
我们来一一解释一下这三个问题都是什么意思:
代码冗余:重复代码量多
可读性差:一段代码有多处重复的地方,令别人看着就头大
可扩展性差:当你的登录功能里有一些小缺陷需要去修复或者添加新内容,需要将每处登录的代码都进行改动。
而有了函数呢:同一功能的代码直接封装成函数,用到该功能就调用函数,大大减少了代码量,可读性变强。同时,我们想要对该功能进行修改时,只需要修改函数内的代码块,而不用一处处的修改。
怎么用函数:
函数的使用必须遵守:先定义再调用(也就是说我们要先将函数制造出来才能使用函数)
定义函数的语法:def 函数名(): def是定义函数的关键字,函数名是后面调用函数的方式。这几个东西缺一不可。
# 定义函数:
def func():
print('我是个函数')
# 调用函数:
func()
定义函数时使用的函数名应该对函数功能具有一定的描述性。
函数分为两大类:内置函数与自定义函数。
内置函数就是python帮我们制造好的函数,我们可以直接拿来使用。例如print(), len(), input(),这些都是内置函数。自定义函数就是我们自己定义的函数,可以方便我们后面使用。
我们使用print()函数时会往括号内传入东西,传入的东西叫做参数,那么我们什么时候才需要往函数内传入参数呢?很简单:当我们写的函数需要我们传入参数时,我们就应该将参数传入进去。最令我们苦恼的是,什么时候函数才需要我们传入参数呢?让我来给你举个例子
def login():
uname = input('请输入用户名>>: ').strip()
pwd = input('password>>: ').strip()
if uname == 'Catalog_Spri' and pwd == 'C_Spri123':
print('login successfull')
return True
else:
print('user or password error')
return False
login()
def max2(x, y):
if x > y:
return x
else:
return y
res = max2(3.3, 1.2)
print(res * 12)
定义login函数时,我们没有要求传入参数,因为我们下面的代码块用不到。定义max2函数时,我们传入了两个参数,在代码块中去比较传入的两个参数的大小。
看了代码,新问题又来了,return是个什么东西?
return的作用很强大:
1. 它可以结束函数:函数运行过程中遇到return会直接结束函数的运行
2. 它可以给你返回一个‘值’:当你需要函数给你一个结果并拿着该结果进行进一步处理时,我们就需要函数给我们一个返回值,给我们的返回值可以是任意类型。
return可以返回任意数量,任意类型的值。如果函数内不写return则默认返回值为None。
函数的使用规则
讲使用规则之前,首先给你们安利一个知识点:
函数的使用分为两个阶段:
1. 函数的定义
2. 函数的调用
在函数的定义阶段,只会简单的判断函数的代码块语法有没有出错。函数的调用阶段才会真正执行函数的代码块。
进入正题:我们来看下面的代码
# 示范一:
def foo(): # 函数定义阶段只会简单判断语法错误。
print('from foo')
bar() # 定义函数并不会执行!!!
foo() # 函数调用的时候会触发函数的代码块,执行函数代码块,这时候就出问题了。
# 因为我们没有事先定义bar函数,在这时候调用bar函数就会报错。
# 示范二:
def bar(): # 示范二可以看出,调用foo函数,执行代码块。bar函数事先定义好
print('from bar') # 所以代码不会报错
def foo():
print('from foo')
bar()
foo()
# # 示范三:
def foo():
print('from foo') # 此处亦不会出错,因为在调用函数之前,我们已经定义好bar函数
bar()
def bar():
print('from bar')
foo()
# 示范四:
def foo():
print('from foo')
bar()
# bar函数定义在我们调用foo函数之后。会报错
foo()
def bar():
print('from bar')
说了这么多,无非是要让你们一定记得:函数要先定义再调用!!!请务必记住
函数定义的三种形式:1. 有参函数; 2. 无参函数; 3. 空函数
上面我们已经讲过怎么定义函数。我们在这里只做简单介绍:
# 1. 无参函数
def func():
print('我是函数')
func()
# 定义函数的时候没有参数就叫做无参函数.无参函数调用时也不能传入参数。
# 2. 有参函数
def func(name, age):
print(name, age)
a = 'Catalog_Spri'
b = 18
func(a, b)
# 定义有参函数时要将参数写入函数名后面的括号内。调用函数时也需要将参数传入进去
# 3. 空函数
def func():
pass
# 这样我们就定义了一个空函数。定义空函数的意义在于先定义好,写主逻辑体系,再回头来写函数代码块
函数的调用
函数的调用也分为三种形式:
1. 语句形式:func() 即函数名加括号直接调用函数
2. 表达式形式:a = func() 可以将函数的返回值赋值给变量a
3. 当做参数传给另一个函数:foo(func()) 可以将函数func的返回值接收到并作为参数传入foo函数
函数的参数(重点)
函数的参数分为两种:1. 形式参数(形参); 2. 实际参数(实参)。
# 形式参数(形参): 在定义函数阶段,括号内定义的参数/变量名称为形参
# 实际参数(实参): 在调用函数阶段,括号内传入的值/变量值称为实参
# ps: 在调用函数阶段会将实参(值)的值绑定给形参(变量名),这种绑定关系只在调用函数时生效,在函数执行完毕后就会解除绑定
def func(x,y):
print(x,y) # 这里的x, y就叫做形参
func(1,2) # 调用函数时传入的参数叫实参,在这里也就是1和2
print(x)
print(y)
细分下来,参数又分为位置参数,关键字参数,默认参数和可变长参数。
# 1. 位置参数
# 1.1 位置形参:在定义阶段,按照从左到右的顺序依次定义的形参称之为位置形参
# 特点:但凡时按照位置定义的形参,必须被传值,多一个不行少一个也不行
def func(name, age, sex):
print(name, age, sex)
# 1.2 位置实参:在调用阶段,按照从左到右的顺序依次传入的值称之为位置实参
# 特点:与形参是一一对应的。
func('Catalog_Spri', 18, 'male')
# 位置形参与位置实参的区别就在于一个是定义阶段一个是调用阶段
# 2. 关键字参数
# 关键字形参:在调用阶段,按照key=value的形式定义的实参称之为关键字实参
# 特点:可以完全打乱顺序,但仍然能为指定的形参传值(总结:指名道姓地为指定的形参传值)
func(age = 18, sex = 'male', name = 'Catalog_Spri')
# 实参的形式可以是位置实参与关键字实参混合使用,但是必须遵循原则:
# 1.位置实参必须放在关键字实参的前面
# 2.不能对同一个形参重复传值
# 3. 默认参数
# 默认参数:在定义阶段,就已经为形参赋值,该形参称之为默认参数
# 特点:
# 1. 定义阶段就已经有值意味着调用阶段可以不用传值
# 2. 位置形参必须放到默认形参的前面
# 3. 默认形参的值在函数定义阶段就已经固定死了,定义阶段之后的改动不会影响该值
# 4. 默认形参的值通常应该是不可变类型
# 举例:print()函数里面有一个参数叫做end,如果不传值,则end默认为\n也就是换行。传入值就会根据传入的值去结束print()函数
# 4. 可变长参数
# 可变长参数:指的是在调用阶段,实参值个数是不固定的
# 可变长参数分为两种,一种是*, 一种是**
# *是用来接收溢出的位置实参,**是用来接收溢出的关键字实参。
# *和**可以联用,一定要遵循**在*后面使用,即:
# def func(*arge, **kwargs):