一、前言
本文章主要讲解Python中的函数定义调用、参数分类、函数使用、作用域以及内置函数等内容,是函数专题讲解,这些都是python自动化学习中的基础哟,只有学好了基础才会有利于后面自动化的学习哟。这里我不多说废话了,直接进入主题吧。
二、函数知识合集
2.1 函数的作用
什么是函数?我们都知道变量的作用,就是用来存储数据的,当我们想使用这个数据时可以调用这个变量从而使用我们需要的数据,函数与变量类似,函数主要是用来存储一段程序的,当我们想使用这段程序时,那么就可以调用函数来进行使用。
2.2 初识函数
函数有三种,第一种是内置函数,第二种是特殊函数(方法),第三种是自定义函数,我们在学习最基础的知识内容时就已经接触到了内置函数与特殊函数,可以看下下方示例:
"""
内置函数
"""
print()
input()
len()
max()
id()
range()
"""
特殊函数
"""
a = ""
a.count()
a.index()
a.find()
a.format()
2.3 函数相关操作
2.3.1 函数定义
刚刚提到了可以自定义函数,函数使用def进行自定义,函数的名称受到标识符的规则限制,在自定义函数中写好我们要的函数体,这样一个自定义函数就完成了,具体详见下方示例:
"""
自定义函数语法:
def 函数名称():
函数体 # 函数要执行的程序或代码
函数名称也是标识符,受到标识符的规则限制
"""
# 自定义函数,名称为hello
def hello():
print("hello,world")
2.3.2 函数调用
根据函数的定义,让我们来执行看一下定义函数的结果:
```python
"""
自定义函数语法:
def 函数名称():
函数体 # 函数要执行的程序或代码
函数名称也是标识符,受到标识符的规则限制
"""
# 自定义函数,名称为hello
def hello():
print("hello,world")
程序已经运行完成了,没有任何的打印,可能有些同学会存在疑问,函数中有打印语句,但为什么这个函数没有执行?实际上函数已经执行了,如果我们想让自定义函数中的函数体生效,必须调用函数,我们只需要输入函数名称加括号就可以进行调用了。
# 自定义函数,名称为hello
def hello():
print("hello,world")
hello() # 调用hello自定义函数
当你进行函数的调用时,就会运行函数体内的代码程序,函数可以多次调用,可以多次使用,但要特别的注意,函数也是有冒号:的,也需要进行缩进,如果我们把调用的内容写在了函数下,那么同样会出现无法调用的情况,代码会判断成这个是一个函数体的内容,而非一个调用:
"""
标准的函数调用:
"""
# 自定义函数,名称为hello
def hello():
print("hello,world")
hello() # 调用hello自定义函数
"""
错误的函数调用:
"""
def hello():
print("hello,world")
hello()
让我们结合for循环来看下使用效果:
"""
标准的函数调用:
"""
# 自定义函数,名称为hello
def hello():
print("hello,world")
# 使用for循环调用10次函数,函数中有一个print,那么调用10次就是执行10次函数体内容,也就是打印10次hello,world
for i in range(10):
hello()
2.3.3 函数返回值(return)
函数的返回值是return,如果没有return默认会返回None,如果用return来接收,那么就会返回接收值,我们先来看一个简单的例子:
# 函数中有return,并且返回的是d,那么调用函数时就是d的值
def number_add():
a = 60
b = 6
c = "大顺"
d = f"{a+b}{c}"
print(f"函数内的值是{d}")
return d
print(f"函数外的值是{number_add()}")
print() # 换行
# 这段函数中没有return值
def number_add1():
e = 60
f = 6
g = "大顺"
h = f"{e+f}{g}"
print(f"函数内的值是{h}")
print(f"函数外的值是{number_add1()}")
如上图所示,第一段代码有2个66大顺的字眼,因为本身函数体内就有一个print,外加上函数体外的打印调用,故此有2个,那么下面的函数有一个66大顺的字眼和一个None,这个打印很明显是函数内打印的,但外面的这个打印返回的结果是None。
在Python中只要有函数必须要有return,return把函数的结果返回给外部,如果没有retrun默认就为None,这点非常重要。
让我们再看一个例子,如下图所示,当我修改了return的值变成一个字符串,那么在函数外部的打印结果则是这个字符串而并非是程序内的执行结果,由此我们可以得出,外部调用并打印函数的内容的具体值不取决于函数内的执行逻辑,而是取决于retrun的返回值:
# 函数中有return,并且返回的是d,那么调用函数时就是d的值
def number_add():
a = 60
b = 6
c = "大顺"
d = f"{a+b}{c}"
print(f"函数内的值是{d}")
return "I love you"
print(f"函数外的值是{number_add()}")
return除了能返回值给外部以外,还有个作用是当函数遇到return时就会终止运行,如下图所示,print在return之后,再次调用这个函数,那么是没有打印的,能够反映出return后的语句是不执行的,示例如下:
def number_add():
a = 60
b = 6
c = "大顺"
d = f"{a+b}{c}"
return "I love you"
print(f"函数内的值是{d}")
number_add()
2.3.4 函数之形式参数
我们已经清楚了函数如何进行调用,如果我们想调用函数改变对应的变量值,我们就可以使用形式参数与实际参数的方式来达到我们想要的目的。
如下代码所示,第一个版本函数的number1和number2的值是固定的,无法修改,我们要打印的话只会有一个结果,但改进版本中,我们移除了number1和number2的变量,把这两个变量作为了形式参数,然后通过打印的方式把我们想要的数值以实际参数的形式代入进去,我们可以理解为给变量实时赋值,这样更加灵活,当我想进行5次,10次的运算,我都可以进行数值的修改,方便灵活,示例如下:
"""
这是最初的版本,我们没有办法修改number1和number2的值,因为他们是固定的
"""
def number_mul():
number1 = 60
number2 = 6
return f"最初版本:{number1} * {number2} = {number1*number2}"
print(number_mul())
print() # 换行
"""
这是改进的版本,我们以变量的方式代入至函数的形式参数中在以实际参数展示变量值
"""
def number_mul(number1, number2): # 这个是形式参数,形式参数写在自定义函数的括号中
return f"{number1} * {number2} = {number1*number2}"
# 当有形式参数时,我们就可以在实际参数位置上填入我们想要的数值,然后以return的方式返回外部,并通过打印语句进行打印输出
print(f"改进版本是:{number_mul(100, 50)}")
2.3.5 函数之位置参数
形式参数必须与实际参数对应,就好比一个变量诞生时必须接收赋值一样,我们把这种对应关系称之为位置参数,如果函数中的形式参数与实际参数不对应,那么执行后就会出现报错,如下代码所示,如果形式参数中提供两个变量值,但在实际参数中只填写一个50,那么执行后就会报TypeError的错误:
def number_mul(number1, number2):
return f"{number1} * {number2} = {number1*number2}"
print(f"改进版本是:{number_mul(50)}")
2.3.6 函数之关键字参数
刚刚有提到形式参数必须与实际参数对应,如果我们一定要改变顺序也并非完全不可以,这个时候我们需要用到关键字参数,关键字参数就直接在实际参数中指明。
如下代码所示,在实际参数中100的值给了number2,而50的值给了number1,这种方式我们称之为关键字参数,我们实际上用输入的数据赋值给了形式参数的变量,这样就达到了位置交换的效果,单纯的交换位置,对结果不影响:
这个时候可能会有的宝宝们比较疑惑,我直接按照关系对应填写保持形式参数和实际参数一致就可以了,为何还需要用到关键字参数?如果形式参数中有很多个参数,例如20个参数,那么你就要对应形式参数去逐一填写你的实际参数,这样就会非常麻烦,但如果我记得变量的话,那么直接进行赋值操作去填写实际参数即可,方便阅读和记忆,更加便捷高效。
def number_mul(number1, number2):
return f"{number1} * {number2} = {number1*number2}"
print(f"改进版本是:{number_mul(number2=100, number1=50)}")
2.2.7 函数之默认参数
默认参数与关键字参数比较相似,默认参数是给形式参数一个默认值,这样我们在调用时传实际参数时就可以少传一个或多个值,如下代码所示,number2在形式参数时默认赋值为10,实际参数的number1变量为2,我们可以直接运行程序且不进行number2的实际参数传参:
def number_mul(number1, number2=10):
return f"{number1} * {number2} = {number1*number2}"
print(f"计算结果为:{number_mul(number1=2)}")
由上图可知,当一个形式参数被赋值后我们称之为默认参数,那么有默认参数的存在,我们是否还可以给这个参数传实际参数呢?也是可以的,如下代码所示,当number2默认为10时,我们也可以在实际参数上传值,以50举例,如果在实际参数上传值后,默认参数将自动失效:
这个时候可能又会有宝宝们有疑问了,那默认参数又有什么用,我只要传了实际参数就可以了吧,为何还需要传默认参数呢?其实当我们有一个默认参数的时候,就可以实现少传参的情况,调用时就更加简单便捷了,因为有一些形式参数并非需要频繁更换的,有一个默认参数,在去调用而不需要传入实际参数会方便许多。
def number_mul(number1, number2=10):
return f"{number1} * {number2} = {number1*number2}"
print(f"计算结果为:{number_mul(number1=2, number2=50)}")
2.2.8 函数之不定长位置参数
不定长位置参数是指在形式参数的变量前加上一个*号,代表不定长位置参数,当有不定长位置参数出现时可以代表不确定具体的参数数值,一个不定长位置参数可以接收多个实际参数,并将数据保存至元组中,通常来说一个不定长位置参数,我们通过*args来表示,这是一个Python规范,如下代码仅做一个演示:
# 这里没有使用*args,请忽略
def number_mul(*number1, number2):
return f"{number1} * {number2} = {number1*number2}"
print(f"计算结果为:{number_mul(5,9,6, number2=3)}")
2.2.9 函数之不定长关键参数
不定长关键参数是指在形式参数的变量前加上两个*号,代表不定长关键参数,不定长关键参数是用于接收关键字参数并保存至一个字典中,通常来说一个不定长关键参数,我们通过**kwargs来表示,这是一个Python规范:
# 这里没有使用**kwargs 请忽略,
def number_mul(number1, *number2, **number3):
print(f"number1是{number1}")
print(f"number2是{number2}")
print(f"number3是{number3}")
return number1,number2,number3
print(f"计算结果为:{number_mul(3,5,9,x=10,a=20)}")
2.2.10 函数之解包操作
通俗的讲在调用时也使用*和**就是解包操作,和不定长位置、关键字参数类似,只不过一个是定义,一个是调用,示例如下:
除了元组以外,列表、字符串都是可以进行拆包操作的。
def number_mul(number1, *number2, **number3):
print(f"number1是{number1}")
print(f"number2是{number2}")
print(f"number3是{number3}")
return number1,number2,number3
A = (1, 2, 3)
print(f"计算结果为:{number_mul(*A,x=10,a=20)}")
2.2.11 内置函数
什么是内置函数,就是Python已经定义好的函数,这些函数不需要我们自定义创建,而可以直接使用,例如print、input等,下面演示一些比较实用的内置函数,在后续自动化测试的工作中会使用到:
"""
eval函数,用于解除字符串两侧的引号
"""
str1 = "7+1"
print(str1)
# 字符串7+1被去除引号后就变成了一个计算
print(eval(str1))
"""
sum函数,求和
"""
print(sum([1, 3, 10]))
"""
zip,压缩
"""
a = ["name", "age"]
b = ["张三三", "永远18"]
# 两个列表可以转换成字典
print(dict(zip(a, b)))
"""
id(),获取一个数据(对象)在内存当中的位置
主要用于判断是否为同一个对象,在内存中存在同样的位置
"""
a = ["name", "age"]
b = "张三三"
c = "张三三"
print(id(a))
# b和c的值是一样的,在内存中的位置也是一样的,说明b和c的变量值在内存中是指向同一个对象
# 字符串是相同位置,但如果是列表的话,位置就会不同,大家可以自行尝试
print(id(b))
print(id(c))
2.3.12 函数参数的注意事项
在函数中关键参数、默认参数都需要写到位置参数的后面,如下示例,这里我做了一下默认参数与位置参数的变换,number1是在number2=10的后面,那么执行后的结果会报SyntaxError错误:
关键字参数如果顺序错误,不在位置参数的前面而是后面,那么也会报错:
"""
如代码所示,number1目前是在number2的后面,这样会报错,因为不允许这样的规则,我们需要把位置参数放到前面
默认参数必须在位置参数的后面才可以
"""
def number_mul(number2=10, number1):
return f"{number1} * {number2} = {number1*number2}"
print(f"计算结果为:{number_mul(number1=2, number2=50)}")
"""
如代码所示,位置参数number1在number2和numebr3的后面,那么这也是不允许的,位置参数必须在关键字参数的前面
位置错误也会报SyntaxError的错误
"""
def number_mul(number1, number2=10, number3=3):
return f"{number1} * {number2} * {number3}= {number1*number2*number3}"
print(f"计算结果为:{number_mul(number2=50,number3=2, number1)}")
除了上述所提到的位置相关的问题以外,我们还需要注意,在整个测试或编码生涯中,只要是自定义的函数,必须要给返回值,必须要有return,如果你真的不清楚要返回什么值,也要写上return,因为没有return的函数是没有任何意义的,这点无论是在练习还是实践,测试还是开发,都是必须要注意的事情,需要牢记在心里。
2.3.13 函数小结
是不是忽然觉得各种函数参数、注意事项等已经眼花缭乱了,笔者特意整理了一个表格,已经学习过怕忘记想重温一下,那么就可以直接看小结的内容。
return的主要作用是用于返回一个值给外部调用,其次是函数执行在碰到return时会终止运行,除此以外无论开发、测试还是其他需要,只要是自定义函数必须加上return,如果没有返回值也必须要有return。
以下是函数参数的几种名称以及对应描述:
2.4 函数作用域
2.4.1 全局变量与局部变量
作用域我们简单的区分为函数内和函数外,函数内就是自定义一个函数,那么函数体的内容我们就称之为函数内,那么非函数体的内容,我们称之为函数外,函数内我们可以定义一个或多个变量,我们把这种变量称之为局部变量,在函数外部所定义的变量,我们称之为全局变量:
"""
这个number1的变量就是局部变量,因为它在函数内部,属于函数体的一部分
"""
def number():
number1 = 10
return number1
print(number())
"""
这个number1是在函数外部的,我们称之为全局变量,它不属于函数的一部分
"""
number1 = 20
print(number1)
细心的小伙伴们已经发现了,之前我们有特别的说过,Python是从上至下运行的,当有一个变量名重复被赋值时,会取最新的赋值结果,前面的赋值结果会被覆盖,在如上代码的例子中,局部变量和全局变量的名称是一致的,但并没有覆盖,这里能够说明,局部变量与全局变量之间互不影响,是相互独立的,不仅如此,各个函数中局部变量名称一致,也不会有冲突,函数与函数间也是独立的。
局部变量的主要作用是用于临时保存数据,故此需要在函数体内定义变量来进行存储。
"""
函数与函数间的局部变量也是独立的单位,函数与函数之间的局部变量重名也不会相互影响
局部变量主要是用于存储临时数据的
"""
def number():
number1 = 10
return f"numebr函数的结果是:{number1}"
def number1():
number1 = 20
return f"numebr1函数的结果是:{number1}"
print(number())
print(number1())
number = 100
print(f"全局变量的结果为:{number}")
细心的小伙伴可能又会发现一个问题,刚刚有提到全局变量函数内和函数外均可以进行调用,那如果局部变量的名称与全局变量的名称一致,在函数内进行print打印,会优先使用局部变量还是全局变量呢?示例如下,从代码和运行结果来看就能很明确的知道,当局部变量和全局变量的名称一致时在函数内进行变量的使用,那么会使用函数体内已经拥有的变量:局部变量是独立的,它只能在自己的函数体内使用,例如number函数下的number1,这个变量就只能在number函数下使用,不能在number1的函数下使用。那么全局变量的number1在文件的任何地方都可以使用。
"""
函数与函数间的局部变量也是独立的单位,函数与函数之间的局部变量重名也不会相互影响
局部变量主要是用于存储临时数据的
"""
def number():
number1 = 10
print(f"尝试调用函数,函数的数值是:{number1}")
return f"numebr函数的结果是:{number1}"
def number1():
number1 = 20
return f"numebr1函数的结果是:{number1}"
print(number())
print(number1())
number1 = 100
print(f"全局变量的结果为:{number1}")
除了上面的知识点以外,还有一个内容就是全局的变量是不能够获取函数体内的局部变量的,如果你尝试获取并执行程序,那么会就报NameError的错误:
"""
函数与函数间的局部变量也是独立的单位,函数与函数之间的局部变量重名也不会相互影响
局部变量主要是用于存储临时数据的
"""
def number1():
number1 = 10
print(f"尝试调用函数,函数的数值是:{number1}")
return f"numebr函数的结果是:{number1}"
def number3():
number2 = 20
return f"numebr1函数的结果是:{number2}"
print(number2)
全局变量是无法直接在函数内进行修改的,默认是在全局进行修改,直接修改会报错:
"""
全局变量不能够在函数内进行修改,如果直接修改会报错
"""
name = "张三三"
def number():
name = name+"love"
number = 2
return number * name
print(number())
要想在函数内修改全局变量,必须要进行声明,声明后就可以在函数内进行全局变量的修改,需要使用global。虽然说global可以声明修改全局变量,但我们在日常的测试中尽可能不要使用,如果每一个维护的人都声明,都去进行修改,最后就会变的非常乱,乱到不可控制的地步,尽可能使用局部变量来进行相关的操作:
"""
声明后,就可以修改全局变量
global 全局变量名
"""
name = "张三三"
def number():
global name
name = name+"love"
number = 2
return number * name
print(number())
2.4.2 函数间的调用
函数间是可以实现调用的,即A函数中可以调用B函数:
def eat(name, food):
print(f"{name}心情不错,吃了一些{food}")
def drink(name, drink):
eat(name, "汉堡")
print(f"{name}同时还喝了一些{drink}")
drink("张三","可乐")
虽然函数间可以互相调用,但函数是不能自己调自己的,如下所示,如果自己调用自己就会出现无限循环的情况,因为Python中有特殊机制,最多可实现993次,超过就会报错,故此最终在执行了993次后报RecursionError的错误:
def eat(name, food):
print(f"{name}心情不错,吃了一些{food}")
eat(name, food)
eat("张三", "汉堡")
最后: 为了回馈铁杆粉丝们,我给大家整理了完整的软件测试视频学习教程,朋友们如果需要可以自行免费领取 【保证100%免费】
全套资料获取方式:点击下方小卡片自行领取即可