
06 函数
今天是给同学们讲解有关函数的知识点,关于函数的知识,在python的任何一个阶段都是非常重要的
对于今天的函数的知识,我们会从四个方面来进行一个了解与学习,
首先第一个函数的定义与调用是对于函数的介绍,学习函数的定义方法、语句格式,以及如何将它调用、使用起来。
第二个是定义了函数之后,为了提高函数的重复使用性,我们会向定义的函数里面添加一些参数,让我们的函数在被调用时能有更多、更丰富得功能,同时也是让定义的函数更加灵活多变。
对于第三个是函数的作用域,主要会向大家介绍,在函数被创建之后的一些特性,对于细节的话在学完函数定义和参数的添加之后再给大家了解。
对于最后的一个,递归函数与匿名函数的话呢,是在我们基础学习阶段一个比较难掌握的点,但是对于这两种函数的话,我们不会经常遇到它,它们自身的概念与前面的函数也有些许的不一样,关于这一点的话,目前只是带着同学们一起去有一个基本的了解,在基础阶段的话很少会用到它,再以后用到它的话,会再拿出来跟同学们进行一个讲解的,同学们要是对于这两种函数有兴趣的话可以在课后去进行一个稍微深入的了解。
那首先进入我们第一点的正题:函数的定义与调用
函数的理解
对于函数的话,我们在学习python基础的时候就已经有一个简单的了解了,例如我们使用的输入输出,print与input
都是算函数,我们可以按住ctrl键,然后鼠标左击进去查看print函数的一个定义方法,可以看到在这个.py文件里有着非常多的函数,这里面包含了所有内置函数定义的代码,可以看到每个函数的函数名,以及在函数名后面的括号里有非常多的内容,像每个函数括号中的内容就是该函数定义的参数,然后对于引号下面的内容,一般都是函数内的一系列功能的定义,但由于这一些函数都是python的内置函数,所以对于里面功能的定义我们都是看不到的,而是使用注释对于这个函数功能的一个讲述,由此可以了解到,对于函数的格式就是由def开头 然后接函数名,函数名之后的括号里面,写的是函数的参数,再使用引号,再在这一行下面使用一个缩进将函数的功能写在函数里面,这样的话就已经是一个完整的函数定义了。
"""
函数
内置函数
print()、input()
自定义函数
# 定义方法
def 函数名(参数):
函数功能
# 函数调用
函数名(参数)
"""
在上一次作业中,有一个对于手机号码判断的题目,只要运行代码,对手机号码进行一个输入,就可以对于输入的数据进行一个判断。
work1 = input('请输入手机号码进行判断:')
if work1[0] == '1':
if len(work1) == 11:
if work1.isdigit():
print('您输入的内容是一个电话号码')
else:
print('您输入的内容不是纯数字,所以该内容不是一个电话号码')
else:
print('您输入内容长度不足11位,所以该内容不是一个电话号码')
else:
print('您输入的内容不是以1开头的,所以该内容不是一个电话号码')
这个代码的缺点是只能对于运行代码之后判断一次,如果我需要在间隔这个代码很远的地方,再次对于这个代码进行一个使用,假如我在这个python文件中写了几百行代码,当我需要再使用它的话,就会非常的麻烦,我总不可能,如果将上面的代码再复制一份,放到下面去,虽说是可行的,但是这样就会有很多重复性的代码,对于代码的阅读流畅性以及资源的占用过多,导致程序运行速度会变慢
此时,函数就能很好的解决这个问题,如果将这一些代码定义成函数,当我想使用这个函数时,只需要进行一个调用,就可以在代码任何地方运行这一些代码,我们可以对于这个判断手机号码的代码定义成一个函数
def isphone():
phone = input('请输入手机号码进行判断:')
if phone[0] == '1':
if len(phone) == 11:
if phone.isdigit():
print('您输入的内容是一个电话号码')
else:
print('您输入的内容不是纯数字,所以该内容不是一个电话号码')
else:
print('您输入内容长度不足11位,所以该内容不是一个电话号码')
else:
print('您输入的内容不是以1开头的,所以该内容不是一个电话号码')
当定义成函数之后,这一些被定义的代码可以作为函数,在代码下面的任何一处地方使用,对于函数的使用,只需要像使用内置函数一样,使用函数名接上括号即可进行一个使用。
同时我们也可以对于函数的名字查询它存在内存中的地址
# print(函数名)
print(isPhone) # 以十六进制的形式,打印出函数存储在内存中的位置
我们可以运行来试一下,在打印出来的后面我们可以看到,像数字和字母这一串文字,是十六进制的形式,该函数存储在内存中的位置。
对于函数,还有一个特性,就是它可以和变量的值一样,能够进行传递,我们可以使用一个变量接收一下函数名
# 函数名能够像变量的值一样被传递,而且该变量还可以跟函数的用法一样
a = isPhone # 把函数名传递给了变量a
a() # isPhone(调用函数)
函数的返回值
对于这一部分没有问题的话,我们就要来了解一下函数的返回值,对于直接打印函数名的功能是查询函数在内存中的地址,那如果打印函数语句的话会是输出什么呢,我们可以来运行试一下
"""
函数的返回值
"""
def test1():
print('这是一个没有返回值的函数')
print(test1())
我们运行后会发现,除了函数内打印的一行数据,同时还出现了一个None值,首先,输出的第一行内容是没有问题的,直接输出了函数中的print的内容,而在打印的第二行返回了一个None值,None的本意是空值,那为什么会返回一个空值呢,这是因为这个test1的函数并没有任何的返回值,对于函数里的内容,可以试用关键字return对于里面的变量的值进行一个返回,我们也可以试一下
"""
函数的返回值
return是表示函数返回值的关键字,
当在函数定义中使用return语句时,其后面的内容将作为函数的返回值,
可以将其赋值给一个变量或者直接用来执行其他操作
return关键字
只有函数能偶使用return,并且return是写在函数的最末尾
"""
def test1():
print('这是一个没有返回值的函数')
print(test1()) # 没有return返回值时,那么会默认返回None值,并且仅仅只是运行函数中的代码
def test2():
return '这是有返回值的函数'
print(test2()) # 函数中有return返回值时,则会打印出return后面的内容
# 赋值给一个变量或者直接用来执行其他操作
a = test2() # 函数可以作为变量值进行传递
print(a()) # 被赋予函数的变量将与变量
对于函数的返回值就是这样的一个用法,再接着的话我们可以来学习一下函数的参数
函数的参数是分为有参函数跟无参函数,像我们之前所写的一些函数,在函数名之后的括号里都没有值传递的函数,都可以称为无参函数,那什么是有参函数呢,对于创造有参函数之前,我们可以来创造一个情景:
假设,现在需要定义一个函数,用于计算两个数的和,并且把计算的结果打印出来,
# 定义一个函数,用于计算两个数的和,并把计算的结果打印出来
def func1():
s = 1 + 2
print(s)
func1()
对于这种方法,当然是可以的,但是太死板了,不能对于相加的数字有一个精确的控制,此时应该又会有同学会想到,当然可以对于相加的数字进行控制,在里面定义两个使用input的变量
def func2():
num1 = int(input('请输入第一个数:'))
num2 = int(input('请输入第二个数:'))
print(num1 + num2)
func2()
这种方法当然也是可以的,但是有没有一种方法,在函数的括号内输入两个数字,之后运行直接输出两个数字的相加结果呢,结果当然是有的,接下来就是学习函数参数中的,有参函数
函数的参数
首先创造一个名叫func3的函数,在函数名后的括号内输入我们所需要两个数字的参数,然后创建一个变量,来接收两个参数的值进行相加,最后使用return关键字返回相加之后的变量,这样的话就是一个正式的有参函数的构造方法了
def func3(num1,num2): # 函数中的有参函数(函数的传参)
result = num1 + num2
return result
print(func3(1, 10))
我们可以对于这个函数进行一个试验,随便输入两个数字,看输出的数据是不是将他们相加,运行之后确实返回了对于这两个数值相加的结果,这样的类型的话,就是函数参数中的有参函数,同时这也叫函数内的传参
同时我们也可以看到,对于函数中的参数与调用函数时里面输入的内容是一一对应的,对于前面的数值对应着第一个参数,而后面的数值对应着后面的参数,我们也可以在函数中,打印一下这两个参数的值,打印出来的结果也是,参数一对应着第一个数值,而参数二对应着第二个数值。在这里还有一个需要注意的点,当在函数中定义两个参数后,调用函数时,里面必须要跟定义函数参数的数量一样,如果不一样就会报错。
这一种被我们称为 必备参数
def func3(num1,num2):
result = num1 + num2
print(f'num1的值为:{num1},num2的值为:{num2}')
return result
print(func3(1, 10)) # 有参函数中的参数,与输入的数值是一一对应的:必备参数
# print(func3(3)) # 调用函数参数与定义参数不对应则会报错
接下来我们继续了解到的是参数中的默认参数,运行函数之前,我们就可以给参数一个默认的值,在进行函数调用的时候,可以不输入这个参数,如果输入了参数的值,则替换掉默认值,在这里我们也可以创造一个情景:
# 定义一个函数,用于结算小时工的工资,默认普通员工为15元/小时,如时薪不一样则自己更改
def salary(hour, hourly_wage=15): # 默认参数
result = hour * hourly_wage
return result
print(salary(11)) # 当参数有默认值时,可以不用添加该参数
print(salary(11, 20)) # 如果需要将默认值更改,则添加参数,输入的参数会覆盖掉默认参数
对于这种在函数中先赋值的参数,我们把它称为默认参数
然后此时,我又想基于上面的内容,再创造一个需求,前面的需求不变,我想再在后面加上,并且写出今天工作的自我评价,然后给自己评分,再在后面记录自己昨天和今天的工时。
def salary(hour, hourly_wage=15, *args, **kwargs):
result = hour * hourly_wage
print(result)
# 不定长参数
print(args) # 使用*args接收没有被定义的元素,以元组的形式保存
print(kwargs) # 使用**kwargs接收已经被定义的元素,以字典的键值对形式保存
# 同时可以对元组类型进行索引查询,对字典进行键查询值
print(args[0])
print(kwargs['day1'])
salary(8, 13, '今天工作较为努力,都没有摸鱼', 9.8, day1 = 8, day2 = 8)
函数的作用域
现在我们来学习函数的作用域,函数的作用域分为全局作用域和局部作用域
对于全局作用域的意义是:函数内部可以访问外部的变量,但是不能直接修改
对于全局作用域是什么意思呢,进入pycharm,给大家进行一个讲述
首先,我创建一个名为num的变量,给他赋值为5。对于这个num变量来说,这个变量在任何函数之外,我们把这个变量称为全局变量
"""
函数的作用域
全局作用域
函数内部可以访问外部的变量,但是不能直接修改
局部作用域
"""
num = 5 # 全局变量:在函数或者类之外的一个变量,称为全局变量
然后,在这个变量的下面创造一个函数,创造一个test1的函数,里面的功能为输出这个全局变量
"""
函数的作用域
全局作用域
函数内部可以访问外部的变量,但是不能直接修改
局部作用域
"""
num = 5 # 全局变量:在函数或者类之外的一个变量,称为全局变量
def test1():
print(num)
test1()
我们来调用一下这个函数,发现对于函数内输出全局变量的状态是正常的,但如果我想给这个变量加一个1呢,我们可以来试一下
"""
函数的作用域
全局作用域
函数内部可以访问外部的变量,但是不能直接修改
局部作用域
"""
num = 5 # 全局变量:在函数或者类之外的一个变量,称为全局变量
def test1():
num += 1 # 在函数中不能对于全局变量直接修改
print(num)
test1()
我们调用函数,运行一下代码,发现会报错,显示局部变量num在赋值前未被声明,那这是为什么呢,咱们可以这样理解,假设num是共享充电宝中的一个充电宝,大家都是可以借用的,但是对于充电宝借用的点位我们是不能改变的。
那在函数中,如果想要将全局变量的值修改,需要一个关键字global来声明该变量为全局变量,从而可以在函数内部修改全局变量的值
"""
函数的作用域
全局作用域
函数内部可以访问外部的变量,但是不能直接修改
局部作用域
"""
num = 5 # 全局变量:在函数或者类之外的一个变量,称为全局变量
def test1():
global num # 使用global关键字声明全局变量后才可以在函数内部修改值
num += 1 # 在函数中不能对于全局变量直接修改
print(num)
test1()
这就是全局作用域的含义
接下来是局部作用域,局部作用域的含义跟全局作用域差不多,对于它的定义是:在嵌套函数中内部函数可以访问外部函数中定义的变量,但是不能修改。
对于局部变量的问题,我们也可以创造一个嵌套函数来尝试一下
def test2():
val = 5
def test3():
print(val)
test3()
test2()
当我们在外部函数定义一个变量,在内部函数中访问外部函数的变量也是可以的,但是对于外部函数的变量的值,也是不能直接修改的,我们也可以尝试一下,在内部函数test3中将外部函数test2()的值加1,运行试一下
def test2():
val = 5
def test3():
val += 1
print(val)
test3()
test2()
运行之后也是跟上面test1()的报错一样,都是局部变量未被声明,对于解决的方法是,使用关键字nonlocal将外部函数的变量进行一个声明,声明之后就可以再内部函数里修改外部函数的变量值了。
def test2():
val = 5 # 在函数内定义的变量称为局部变量
def test3():
nonlocal val # 使用nonlocal关键字声明外部函数的变量后才可以在内部函数里修改外部函数的变量
val += 1 # 在内部函数中无法直接修改外部函数的变量值
print(val)
test3()
test2()
闭包
对于函数作用域在这里还有一个特性,叫闭包,对于闭包的最简单的解释是方便对嵌套的函数进行访问
对于它的优势是隐藏了嵌套函数中内部函数调用的代码,同时可以保护代码不被外部程序访问或修改
def test5():
var = 0
def test6():
nonlocal var
var += 1
print(var)
return test6 # 与普通内嵌函数不一样的唯一一点:嵌套的外部函数会将内部函数名作为返回值返回
a = test5()
a()
递归函数
"""
递归函数:
n * n-1 * n-2 * ..... * 1
等同于数学中的阶乘 例如:
n = 5
递归函数的内容为
5 * 4 * 3 * 2 * 1
"""
# 使用for循环计算阶乘
num1 = 1
for i in range(1,6):
num1 *= i
print(num1)
# 创建递归函数
def func(n):
if n <= 1:
return 1
else:
return n * func(n - 1) # 5 * 4 * 3 * 2 * 1
print(func(10))
本节课最后一个知识点:匿名函数
"""
匿名函数
无需使用def关键字定义函数,使用lambda将函数写成一行,用变量接收,并且变量作为函数名
"""
add = lambda x, y: x + y # 使用变量接收匿名函数的内容,且变量名作为函数名
# 在sort方法中的key参数可以使用lambda来定义排序前对每个元素的操作
li = ['watermelon','apple','banana']
li.sort(key=lambda x:len(x)) # 使用lambda关键字设置排序要求:以列表中字符串的长度进行排序
print(li)