前言
在解决相同问题不同变量的时候,我们只需要定义好一个函数,然后将这些变量反复使用这些函数即可解决问题,不需要我们去手动计算,计算机会帮助我们更准确迅速的解决问题。
函数可以帮助我们完成更简洁的代码、减少代码的重复、易于测试、快速开发、便于团队合作,因此在后面的学习过程中,函数是必不可少的一环。
1. 函数使用
1.1 定义
函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
函数内容以冒号 : 起始,并且缩进。
return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回 None。
1.2 创建
函数的定义使用的关键字是def,定义函数的一般形式为:
def function_name():
函数内容
需要注意几点:
- 关键字不能作为函数名字。
- 函数名中不能存在空格。
- 函数名的首字母必须是大小写字母或者下划线。
- 函数名的其余字母可以使用字母、数字以及下划线。
- 不同函数名大小写不同的时候为不同函数。
采用字母+下划线+字母的形式为常用的命名方式。
def get_name():
pass
def get_salary():
pass
def add_money():
pass
1.3 调用
当我们创建好函数之后,如果不调用的话,不管函数中有多少print都不会执行的,因为函数就像我们买了一些工具放在仓库里,只有当我们拿出来的时候才能去使用,因此我们需要调用函数。
调用函数的时候,解释器会跳到函数体内,执行函数内的语句,当执行完毕之后回到调用的位置继续执行后续语句。
def helloworld():
print('调用函数')
print('helloworld')
print('人生苦短,我用Python')
if __name__ == '__main__':
helloworld()
print('调用完毕')
2. 参数传递
打个比方来说,我们买来了一个榨汁机,当我们加入苹果的时候会出来苹果汁,加入西瓜的时候会出来西瓜汁,参数就起到这样一个作用,参数通过主函数传递到被调用函数,然后被调用函数会返回给我们一个结果。
2.1 形参和实参
- 形式参数为我们定义函数的时候再括号中定义的参数,我们在函数的内部会使用这个参数进行代码的编写,
- 而实际参数为函数调用的时候传进来的参数,函数返回的结果是根据这个实际参数来代替形式参数。
A = 30 # 30天
def get_salary(days):
salary = days * 50 # 工资算法
print(salary)
get_salary(A)
参数days为形式参数,在我们调用函数的时候,A即为实际参数,实际要带入到函数中使用的参数。
2.2 位置参数
我们在创建函数的时候可以在括号中定义多个形式参数,
我们在调用的时候,参数的数量和位置需要和创建的保持一致。
- 参数的数量不一致
如果我们创建的函数中有2个形式参数,而我们调用的时候只使用了1个实际参数,会是什么样的结果呢?
def get_message(address,number):
print(address,number)
get_message('苏州','1')
get_message('杭州')
我们可以发现当实际参数的数量不等于形式参数的数量时候,会抛出异常,具体的意思为缺少一个必要位置的参数number。
2) 参数的位置不一致
当参数的位置不一致的时候会导致出现两种错误,
- 一种是直接报错,因为我们在传参的时候会根据参数的性质而定义不同的类型,因此数据类型的错误会抛出异常。
- 另外一种错误是传入的参数的数据类型是对的,但是位置是错的,这样会出现错误的输出结果。
2.3 关键字参数
使用关键字参数可以省去定义变量的过程,直接在函数调用的时候给参数进行赋值,然后传递到函数当中,最后返回结果。在这种传递方式中,参数位置的不同是不影响输出结果的。
def volume(length,width,height):
volume = length * width * height
print('体积为:', volume)
volume(20,30,3)
volume(length=20,width=30,height=4)
2.4 参数默认值
当我们定义一个函数的时候,可以给函数的参数定义一个初始值,这样在我们调用函数的时候如果没有给出实际参数,那么函数会使用默认参数。
def volume(length=100, width=100, height=10):
volume = length * width * height
print('体积为:', volume)
volume()#不给出实际参数的时候会使用默认参数100000
volume(10,10,10)#给出实际参数会传递实际参数给出输出结果
2.5 可变参数
在Python中函数的参数个数是可以变化的,也就是说参数的数量可以是不确定的,这种参数被称为可变参数。
可变参数分为两种,一种是参数前加*,这种方式的可变参数在传递的时候是以元组的形式传递,
一种是参数前加**,这种方式的可变参数在传递的时候以字典的形式传递,我们主要介绍一下第一种方式。
def add_number(*number):
add_num = 0
for i in number:
add_num += i
print(add_num)
add_number(1,2,3,4,5)
使用可变参数的时候,这些参数会被存放在一个元组中传递到函数里,因此我们要使用这些参数的时候可以使用遍历或者索引值进行使用。
函数的参数传递大致就是这些,想要学好函数,一定要掌握好参数的传递,参数的正确传递在函数的使用过程中至关重要。
3. 返回值
我们在使用函数的过程中通常是调用函数,然后被调用的函数中的内容会依次被执行,但是我们有的时候需要的不只是执行的步骤,我们还需要获取到函数中的一些变量,因此我们在使用函数的时候还可以增添一个返回值来获取函数中的一些数据。
def get_sum(a, b):
sum = a + b
return sum
get_sum(1, 2)
def get_sum(a, b):
sum = a + b
print('调用了这个函数')
return sum
print('完成返回值的传递')
s = get_sum(1, 2)
print(s)
3.1 多值返回
其实我们在返回多个值的时候原理和一个值的时候类似,我们需要注意的一点是当我们返回的是多个值的时候,多个值是被存储在元组当中的。
def get_data():
a = 1
b = 2
c = 3
d = 4
return a, b, c, d
print('返回值的类型:', type(get_data()))
print('返回值:', get_data())
def get_data():
a = 1
b = 2
c = 5
d = 4
return a, b, c, d
print('返回值的类型:', type(get_data()))
print('返回值:', get_data())
i,o,k,l = get_data()
print(i,o,k,l)
for i in get_data():
print('这是返回的第%d个数据'%i)
4. 变量
变量的作用域值的是一个变量能够有效的区域,因为我们在使用函数的时候,有的变量是在主程序中定义的,有的是在调用的函数中定义的,当我们的主程序使用函数中定义的变量时,就会出现异常。
4.1 局部变量
局部变量,顾名思义,就是作用在局部区域的变量,如果是在函数中定义的变量,那么就只在函数中起作用,如果在函数外部使用函数内部的变量,就会出现异常。
def test():
data = '局部变量'
print('在函数内部输出data为:', data)
test()
print('在主程序中输出data:', data)
由于变量data是在函数内部定义的,我们在主程序中使用变量data则会出现访问的变量不存在的问题,所以我们要注意在函数内部定义的变量为局部变量,未作特别声明的话是不可以在函数外使用的。
4.2 全局变量
全局变量我们也可以从字面意思中理解到它就是作用在全局的变量,有的同学可能自然而然的认为那么全局变量一定是定义在主程序中的变量了,其实全局变量也是可以作用在函数中的
两种全局变量的使用方式:
- 在主程序中定义全局变量。
data = '全局变量data'
def test():
print('这是作用在函数【中】的全局变量:',data)
test()
print('这是作用在函数【外】的全局变量:',data)
2) 使用global关键字
我们在函数内定义的变量也可以编程全局变量,这时候我们就要使用到global关键字。
data = '这里是全局变量data'
print(data)
def test():
data = '这里是局部变量data'
print(data)
test()
print('再检查一下全局变量data:',data)
全局变量和局部变量的命名相同的时候是不影响全局变量的内容的,但是如果我们想要在函数中修改全局变量的值,那么我们就要使用global关键字。
data = '这里是全局变量data'
print(data)
def test():
global data
data = '这里是局部变量data'
print(data)
test()
print('再检查一下全局变量data:',data)
通过global关键字,在局部中声明告诉这个函数global是一个全局变量,那么修改了之后,全局中的变量都做了修改,global关键字就是可以使一个变量变成全局变量。
def test():
global data
data = '这是在局部创建的变量data'
print('这是在函数中输出:', data)
test()
print('这是在主程序中输出:', data)
当全局中没有声明变量的时候,我们在局部中也可以使用global关键字直接来声明一个变量是全局变量,那么我们在函数中定义的变量在主程序中也是可以使用的
5. 函数种类
5.1 匿名函数
匿名就是指没有名字,我们在写程序的过程中有时不需要给函数命名,这时候就可以使用匿名函数,我们在Python中使用lambda表达式来使用匿名函数。
5.1.1 匿名函数的定义
m = int(input('请输入一个数字:'))#m为输入的值
a = lambda x : x * x #使用变量a来构成一个表达式
print('返回值为:',a(m))
lambda表达式等同于把函数压缩为一行代码,然后通过变量的定义直接来调用这个函数,这种方式可以简化我们的代码。
5.1.1 序列调用匿名方法
my_list = [1,4,6,9,12,23,25,28,36,38,41,56,63,77,88,99]
print(list(filter(lambda x : x % 2 == 0,my_list)))
filter()函数中的对象前者为我们的筛选方式,后者为我们要筛选的对象,然后我们把这些数据使用list()函数存放在了列表当中,最后打印出来,这种方式可以帮助我们很快的进行数据的整合。
my_list = [('元组甲',15,33),('元组乙',25,26),('元组丙',7,7)]
my_list.sort(key=lambda x : x [2] - x[1])#使用key关键字来引入排序方式,排序方式根据第三个元素减去第二个元素的差值,对应索引为2和1
print(my_list)
他们的差值分别为18、1、0,所以他们的排列顺序应该为丙、乙、甲,通过lambda表达式中的返回结果x[2]-x[1],我们获得了他们的差值,然后根据差值进行排序。
匿名函数在数据筛选的时候显得尤为重要,它能够很快的帮助我们来解决数据复杂繁琐的问题,同时它可以优化我们的代码,使得代码的整体更为简洁。
5.1 基础函数(3个)
5.1.1 filter()过滤函数
在数据筛选和过滤的时候我们通常会采用filter()函数帮助我们快速的解决问题,它的语法格式为:
filter(函数,可迭代对象)
在filter函数中,前面放我们的过滤或筛选方式,即函数名,后面存放可迭代的对象
def test(x):
if x % 2 == 0:
return x
my_list = [1,2,3,4,5,6]
print(filter(test,my_list))#只需要些函数名即可,不用加参数
在这里我们需要注意filter()函数的返回值为一个可迭代的对象,
我们需要通过迭代的方式访问其中的值,或者使用列表list()函数强制类型转换。
def test(x):
if x % 2 == 0:
return x
my_list = [1,2,3,4,5,6]
print(filter(test,my_list))
for i in filter(test,my_list):
print('迭代后中的数据:',i)
print('使用list()方法:',list(filter(test,my_list)))
5.1.2 map()映射函数
map()函数的语法格式为:
map(函数,可迭代对象)
在使用map()函数的时候,我们大多用于对数据的处理,把可迭代对象中的数据经过函数处理之后存储,我们在存储的时候继续采用list()函数进行存储。
# 在一个列表中存放了一下字母,如果存在小写字母,那么将它变成大写字母。
def test(x):
if x.islower():
return x.upper()
else:
return x
my_list = ['d', 'o', 't', 'C', 'p', 'P']
print(list(map(test, my_list)))
test()函数中会先对x进行判断,如果是小写字母就返回它的大写字母,如果不是小写字母就返回它的值。
5.1.3 reduce()聚合函数
reduce()函数用于把可迭代的对象通过函数方法进行聚合。 语法格式为:
reduce(函数, 可迭代对象[, 初始值])
# 已知一个列表为[1,2,3,4],我们需要求列表里所有项依次相乘的和
from functools import reduce #reduce函数在functools模块中定义,需要引入
def test(x,y):
return x * y
my_list = [1,2,3,4]
print(reduce(test,my_list))
5.2 递归函数
需要注意:
1) 递归是在函数本身调用函数本身。
2) 递归的效率比较低,如果有时间限制不建议使用。
3) 递归过程中需要有一个明确的结束条件,即递归出口。
m = int(input('输入一个数字:'))
def test(x):
x += 2
if x <100:
test(x)
else:
print('最后的x为:',x)
test(m)
5.2.1 斐波那契数列
斐波那契数列的递推公式为F(n)=F(n-1)+F(n-2),F(1)、和F(2)为1。
F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)
数列:1、1、2、3、5、8、13、21、34、……
N = int(input("输入需要得到的项数:"))
def fibonacci(n):
if n <= 2:#如果小于等于2就把n置1
return 1
else:
return fibonacci(n-1) + fibonacci(n-2)
print('对应值为',fibonacci(N))
其实这种方式的求解是比较浪费时间的,因为需要进行迭代的次数太多,我们还可以采用空间替代时间的方式来求解这个问题。
n = int(input("输入需要得到的项数:"))
fibonacci = [1,1]
for i in range(2,n):
fibonacci.append(fibonacci[i-1] + fibonacci[i-2])
print('对应值为',fibonacci[n-1])
这种方式我们首先给列表规定了前2项的值,然后对于我们要求解的项数n,我们直接通过公式把这个斐波那契数列的列表填充到我们需要的那一项,最后根据索引值直接找到对应项输出结果。
5.2.2 汉诺塔
…