函数解包
"""
1、函数的注释:参数和返回值 在注释里可以自动添加显示,只需手动加说明。
2、函数的解包【拆包】:函数的参数要传递数据有多个值的时候,中间步骤拿到数据 保存在元组或者列表 或者字典里。
- 传递参数的时候 加一个* 或者 ** 解包
- 一次拿到元组 列表 字典的里数据 直接传递给函数的参数接受。
- 定义参数的额*args **keargs == 定义函数
"""
def send_offer(salary,bonus,subsidy=500):
"""
这是一个发送offer的函数
:param salary: 底薪
:param bonus: 提成
:param subsidy: 补助
:param args: 不定长参数 薪资其他的组成
:param kwargs: 不定长参数 薪资其他的组成
:return: 返回薪资总共
"""
smoney = salary + bonus + subsidy
return smoney # 定义smoney为函数返回值
# 参数数据保存在元组里,依次获取里面每一个数据 传参
param = (18000,3000,200)
# 传统方式 麻烦。
print('传统方式',send_offer(param[0],param[1],param[2]))
# 元组解包传参 : 元组前面加一个* 可以依次获取元组里每一个数据 按照位置顺序的传递给函数参数
print('元组解包传参'+str(send_offer(*param)))
# 列表解包
param = [18000,3000,200]
print(send_offer(*param))
# 字典解包 --键值对 : 字典跟顺序没关系,字典的key跟关键字名字【形参】对应就可以。
param = {"salary":17000,"bonus":2000,"subsidy":300}
# 传统方式 -- 多麻烦
print(send_offer(salary=param["salary"], bonus=param["bonus"], subsidy=param["subsidy"]))
# 字典解包
print(send_offer(**param))
函数的调用
函数里调用其他的函数:
注意: 函数执行原理顺序
- 顶格代码 同级别: 从上到下依次执行。
- 缩进代码: 函数体代码 ,只有在函数调用的时候的才会执行。
debug新用法:
- step over : 第一个单步,不会进入函数或者方法里面执行
- step into : 第二个【进入所有的函数和方法】 和第三个【只会自己定义函数和方法】
问题: 函数可以调用自己么?
= 会出现递归错误 函数不要调用自己。
# def get_offer(name):
# """拿offer函数: 某个人 拿到x钱offer"""
# # 调用send_offer函数
# money = send_offer(16000,2000,800)
# return f'{name}拿到了一个{money}工资的offer!'
#
# def send_offer(salary,bonus,subsidy=500):
# smoney = salary + bonus + subsidy
# return smoney
#
# print(get_offer("芒果"))
def get_offer(name):
"""拿offer函数: 某个人 拿到x钱offer"""
# 调用send_offer函数
money = get_offer("我")
print(money)
return f'{name}拿到了一个{money}工资的offer!'
get_offer("我")
如上自己调用自己就会报错:
函数的作用域
函数的作用域: 函数内部 和函数外部
- 局部变量: 函数里定义的变量,不能在外面的调用。 【买的苹果】 私有财产 不能给别人使用
- 全局变量:在函数外面定义的变量,在函数里面可以调用。 【小区的公共苹果】 所有人都可以拿
- 全局变量函数可以调用,但是不能在函数内部去修改 【苹果可以吃 但是苹果树砍了不行】
- 如果提前申明了 是可以修改 【但是跟物业申请了 可以砍了】
- 在局部修改了全局变量值 生效。
– 注意: 不建议在局部修改全局变量,容易造成别人调用了全局变量会被影响。
# add函数里的ab 变量 是局部还是全局的? -局部变量
c = 3 # 全局变量
def add(a,b):
global c # 申明全局变量 -- 用得很少
c += 1
return a + b -c
# print(a) # 局部变量不能在函数外面使用的
print(add(2,3))
print(c) # 在局部修改了全局变量值 生效。
运行结果如下:
1
4
函数的封装
函数是不是基本上所有功能代码都可以被封装成函数?-- 可以。但是并不是所有的都需要封装。
– 只有哪些需要多次 重复使用功能代码。–调用。
封装函数步骤:
1、先分析求 把功能代码写好
2、def 封装 [功能代码缩进变成函数体]
3、函数参数化:变化的数据 或者用户控制输入的数据 定义为形参
4、判断函数是否需要定义返回值:获取数据 有就返回; 没有不定义返回值。
def buy(price):
discount = "0"
if price.isdigit(): # 判断是否输入的是数字
if 50 <= int(price) <= 100:
price = int(price) * 0.9
discount = "10%"
elif int(price) > 100:
price = int(price) * 0.8
discount = "20%"
return f"折扣为:{discount},最终要付的金额为:{price}"
else:
return "请输入数字"
print(buy("200"))
运行结果如下:
折扣为:20%,最终要付的金额为:160.0
内置函数
总结内置函数:安装Python软件的时候,已经内部定义好的 可以直接使用的函数。
- ctrl + 点击函数名字 == =builtin 描述文件,参数 使用方法和功能等信息。 底层是c语言封装的。
- 内置函数有很多,不需要目前全掌握 先掌握用的频率较高。
常用的内置函数
- print input
- len
- type isinstance
- range()
- str int float list tuple set dict
- 字符串的方法: str.find , .index .lower .upper .join .strip .replace .split .endswith .startswith 。。。
- 列表方法: .append .extexd .insert .pop .remove ,.count
- 字典方法: .update .get .keys .values .item() .pop
print: 参数: * args可以接受多个参数;
- sep=’ ’ : 默认值是空格,所以多个参数之间用这个字符隔开 ,可以传参
- end=‘\n’,每个print语句最后都会换行 默认换行符;–也可以修改 传参
print(“乖乖”,“余”,“芒果”,sep=“–”,end=“*”)
print(“乖乖”,“余”,“芒果”,sep=“–”)
eval()
eval(): 函数用来执行一个字符串表达式,并返回表达式的值。 == 脱引号获取及运行字符串里的Python表达式。
字符串表达式可以包含变量、函数调用、运算符和其他 Python 语法元素。
使用场景1 : 接口测试的时候,测试数据存在excel里【文本-字符串】;代码读取出来,存在字典和列表。-- 脱引号 转化字典
使用场景2 : 接口测试数据参数化,excel表格里数据生成,在excel表格里调用数据生成函数。
eval不是万能的,有些字符串不能用的 只要那些字符串里的表达式符合Python语法的才可以。
参考文章 :http://testingpai.com/article/1692240611928
# eval()
a = "1 + 4" # 字符串
print(a) # 结果 "1 + 4"
print(eval(a)) # 脱引号 运算引号里的Python表达式 1+4
a = '{"name":"itop","age":18}' #在字典外面加了一对引号 字符串
print(a,type(a))
print(eval(a),type(eval(a)))
# 接口测试的时候,测试数据存在excel里【文本-字符串】;代码读取出来,存在字典和列表。-- 脱引号 转化字典
# 函数调用
def p_test():
print("hello world")
# "test()" # 这样不行调用函数
# eval执行字符串里函数调用
eval("p_test()")
# 异常场景 --有一个null 在Python里是不能被识别的 异常符合。None
a = '{"name":"itop","age":18,"hobby":null}'
print(eval(a),type(eval(a)))
运行结果如下:
1 + 4
5
{"name":"itop","age":18} <class 'str'>
{'name': 'itop', 'age': 18} <class 'dict'>
hello world
Traceback (most recent call last):
File "D:\BaiduNetdiskDownload\1-Python基础\20231110_py65基础第六节课-函数和文件处理\day06_函数和文件处理\day06_函数和文件处理\d5_内置函数和eval函数.py", line 54, in <module>
print(eval(a),type(eval(a)))
File "<string>", line 1, in <module>
NameError: name 'null' is not defined
zip()
zip(): 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
- 如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。
使用场景: 接口测试测试用例保存在字典里,方便数据读取。{“id”:1,“title”:“注册成功”}
a = ["a","b","c"]
b = [1,2,3,4]
print(list(zip(a, b))) #压缩并转化为列表嵌套元组 [('a', 1), ('b', 2), ('c', 3)]
print(dict(zip(a, b))) # 压缩成为键值对 的字典 key value {'a': 1, 'b': 2, 'c': 3} ==这种用更多
# 用例 == 压缩成为字典
title = ["id","title","testdata"] # 作为保存用例的字典的key
case1 = ["1","注册成功","123456"]
case2 = ["2","注册失败","123456"]
print(dict(zip(title, case1))) # {'id': '1', 'title': '注册成功', 'testdata': '123456'}
print(dict(zip(title, case2)))
# 项目里实战: 二维数据 --模拟excel里存储 行列
# 所有的用例放在大列表里,每条用例存在字典里 [{},{},{},{}]
testcases = [["id","title","testdata"],
["1","注册成功","123456"],
["2","注册失败","123456"]]
title = testcases[0] # 先获取标题 用来作为字典的key
new_list = []
for case in testcases[1:]: # 从第二行开始读取 不需要标题行
dict_case = dict(zip(title,case)) # 一条用例 字典
new_list.append(dict_case)
print(new_list)
# 优化写法: 列表推导式
testcases = [["id","title","testdata"],
["1","注册成功","123456"],
["2","注册失败","123456"]]
title = testcases[0]
new_case = [dict(zip(title,case)) for case in testcases[1:]]
print(new_case)
运行结果如下:
[('a', 1), ('b', 2), ('c', 3)]
{'a': 1, 'b': 2, 'c': 3}
{'id': '1', 'title': '注册成功', 'testdata': '123456'}
{'id': '2', 'title': '注册失败', 'testdata': '123456'}
[{'id': '1', 'title': '注册成功', 'testdata': '123456'}, {'id': '2', 'title': '注册失败', 'testdata': '123456'}]
[{'id': '1', 'title': '注册成功', 'testdata': '123456'}, {'id': '2', 'title': '注册失败', 'testdata': '123456'}]
open()
open(): 函数用于打开一个文件,创建一个 file 对象,相关的方法才可以调用它进行读写。
- 数据存储到文件里-- 写入文件数据
- 配置文件: 数据库 项目的地址等 放在文本里进行统一管理,读取里面数据-- 文件的读取
- UI自动化-- 截图保存图片
文件处理的操作:
- 打开文件
- 读取文件内容
- 写入内容到文件
- 关闭文件 :文件打开了 一定要记得关闭。不关闭再次使用的时候 容易冲突 报错。
文件里有中文: UnicodeDecodeError: ‘gbk’ codec can’t decode byte 0x86 in position 47: illegal multibyte sequence
- 打开文件的时候 加上编码 UTF8编码。
- 语言默认只能处理英文,编码ASCII编码,国际编码通用-UTF8。 加上参数: encoding=“UTF8” 默认加上。
mode :
- r 读取
- w: 覆盖之前内容 写入
- a: 追加写入 == 更常用 更安全
- x: 写入 写入新文件 不能是已经存在的文件,直接生成新的文件并写入内容
- b: 写入文件不是文本,图片 视频等 二进制流的格式 ; 不单独用,配合以上读写模式一起用
- rb
- wb
- ab
注意: 不能加encoding=“UTF8”。
读取
demo文本内容如下:我希望名可以继续捡10块钱我希望名可以继续捡10块钱我希望明天可以继续捡10块钱
# open 打开文件 读取里面内容
f = open("demo",encoding="UTF8")
# print(f) # 对象,通过他可以进行后续操作
data = f.read() # 读取数据 赋值给data变量
print(data)
# 关闭文件
f.close()
运行结果如下:
我希望名可以继续捡10块钱我希望名可以继续捡10块钱我希望明天可以继续捡10块钱
写入
# open 写入数据-- mode 默认是读的模式 不能写入。 修改mode为w 【write】
# f = open("demo",encoding="UTF8",mode="a")
# f.write("我希望明天可以继续捡10块钱")
# f = open("demo",encoding="UTF8",mode="w")
# f.write("我希望明天可以继续捡10块钱")
# f = open("demo1",encoding="UTF8",mode="x")
# f.write("我希望明天可以继续捡10块钱")
f = open("tricy.png",mode="rb")
data = f.read() # 图片内容 是十六进制格式
print(data)
f.close()
# 复制一张图片 --把写入内容
f = open("tri2.png",mode="wb")
f.write(data)
f.close()
逐行读取
当文档里有很多内容的时候,一次性读取写入处理不太灵活,很多时候需要逐行读取和写入操作。–方便拿到想要的数据。
- 逐行读取 : readlines()
- 按照行数一次性读取多行,存在列表里,每一行的数据【字符串】是列表的一个元素。
- 注意默认把行末 的换行符读出来\n,如果不需要换行符,去除strip
- 逐行写入: writelines()
- 把多个数据存在列表/元组的元素,依次逐个写到文本里;
- 但是注意: 列表里的元素必须要是字符串。
- 注意: 写入过程没有间隔符 和换行符等,如果需要 手动添加 \n \t
# 逐行读取 : readlines()
# f = open("demo",encoding="UTF8")
# data = f.readlines()
# print(data)
#
# # 去除每行读取数据的末尾的换行符 - strip
# new_data = []
# for a in data:
# new_a = a.strip("\n") # 去除换行符之后赋值给变量
# new_data.append(new_a) # 再追加到新的列表里
# print(new_data)
# f.close()
# 逐行写入: writelines()
f = open("demo",mode="a",encoding="UTF8") # 追加模式 a
data = ["\nname ","age\t","hobby\t"]
f.writelines(data) # 可以逐个把列表的每一个元素 依次取出来写到文本里
f.close()
with方式打开文本
with方式打开文本: 自带关闭,自动关闭文件 不需要手动添加close代码。 --推荐使用写法
- 子代码 写上文件相关的操作代码
- 不用close方法 不会忘记关闭文件。
with open("demo",encoding="UTF8",mode="r") as f:
data = f.read()
print(data)