【Python测试开发】Python基础篇

如何从 0 开始学 Python 自动化测试开发_python 开发自动化 3. 然后,熟悉接口测试中的 Requests,APP 自动化测试的 Appium, Web自动化的 Selenium,数据库的连接和操作库 pymysql,还可以简单的了解下 Windows 下 GUI 的自动化测试库 pywinauto。6. 另外,最好能找到一个既懂 Python 又懂测试开发的导师或朋友,请教学习规划和建议,最重要的是在遇到卡壳的地方请他指点,这样会事半功倍,少走很多弯路。在入门过程中,选择一本好的入门书是非常关键的事情,这直接关系到你是****从入门到精通还是从。 阅读详情

一、 变量

1.1 命名规则

  • 以字母(大小写均可)开头,由字母、数字、下划线组成。
  • 不能使用Python关键字作为变量名。

1.2 其他注意事项

  1. input输入的内容都是保存成字符串类型的
age = input("请输入你的年龄:")
print(type(age))

在这里插入图片描述
2. print()输出两个或两个以上变量,变量间直接使用逗号隔开
3. 同时输出两个或两个以上变量所对应的值时,两个值中间默认使用空格作为分隔符,可以用sep=参数指定分隔符

age = input("请输入你的年龄:")
name = "Lucifer"
gender = "female"
print(age, name, gender, sep="#")

在这里插入图片描述

二、Python运算符

2.1 算术运算

+:加法运算符
-:减法运算符
*:乘法运算符
/:除法运算符(结果为小数)
//:取整(求商)运算符(结果为整数)
%:取余数运算符
**:乘方运算符

【注意】:

# 字符串的乘法
s = "hello"
n = s * 100
print(n)

在这里插入图片描述

2.2 比较运算

==:检查两个值是否相等
!=:检查两个值是否不相等
>:检查一个值是否大于另一个值
<:检查一个值是否小于另一个值
>=:检查一个值是否大于或等于另一个值
<=:检查一个值是否小于或等于另一个值

2.3 逻辑运算

 and:逻辑与,当两个条件都为True时,返回True 
 or:逻辑或,当两个条件至少一个为True时,返回True 
 not:逻辑非,将True转换为False,将False转换为True

三、字符串操作

3.1 字符串下标

  1. 字符串是有下标索引的,是为了方便查询。
  2. 下标索引有两种表示方式:正数表示和负数表示。
  3. 正数下标是从左至右,从0开始,最后一个元素的下标是:len(字符串)-1。
  4. 负数下标是从右往左,从-1开始,最后一个元素的下标是:-len(字符串)
  5. 截取字符串某段内容时,:左边是开始位置的下标,右边是结束位置的下标,按照从左到右的顺序。该区间为左闭右开区间。
a = "helloworld"

# 截取low
print(a[3: 6])      # 正数表示
print(a[-7: -4])    # 负数表示   注意:前后是从左到右的顺序
  1. 如果截取的是某个下标之后的内容,则:后的内容可以不写。
# 截取world
print(a[5:])
print(a[-5:])
  1. 如果截取的是某个下标之前的内容,则:前的内容可以不写。
a = "helloworld"

# 截取hello
print(a[:5])
print(a[:-5])

3.2 字符串格式化

方式一:%s

  • 每一个%s接收一个值,按顺序传入
name = input("请输入姓名:")
age = input("请输入年龄:")

# 按照”谁的年龄是多少岁“格式输出
new_str = "%s的年龄是%s岁" % (name, age)
print(new_str)

在这里插入图片描述

方式二:format

  • format方式如果不指定参数传递的顺序,则按照位置顺序传入
  • 如果指定了传入顺序,对于后面.format(name, age):name的下标是0,age的下标是1。
name = input("请输入姓名:")
age = input("请输入年龄:")

# 按照”谁的年龄是多少岁“格式输出
# 不指定传入顺序
new_str = "{}的年龄是{}岁".format(name, age)

# 指定传入顺序
new_str1 = "{1}的年龄是{0}岁".format(name, age)
print(new_str)
print(new_str1)

1

方式三:f-str

name = input("请输入姓名:")
age = input("请输入年龄:")

# 按照”谁的年龄是多少岁“格式输出
new_str = f"{name}的年龄是{age}岁"
print(new_str)

在这里插入图片描述

3.3 字符串相关内置函数使用

  1. len(str):返回字符串长度
str = "helloworld"
print(len(str))
  1. count(str, beg=0, end=len(string)):返回str在string中出现的次数;如果beg和end指定,则返回指定范围中str出现的次数。
>>> str = "helloworld"
>>> print(str.count("o"))
2
  1. capitalize():将字符串的第一个字符转换为大写
>>> str = "helloworld"
>>> print(str.capitalize())
Helloworld
  1. center(wadth, fillchar):返回一个指定宽度的,居中的字符串,fillchar为填充的字符,默认为空格。
>>> str = "helloworld"
>>> print(str.center(50, '*'))
********************helloworld********************
  1. find(str, beg=0, end=len(string)):检测str是否包含在字符串中。如果指定beg和end,则检查在指定范围内是否包含str,如果包含,则返回第一个所找字符的下标;如果不包含,则返回-1。
# 要查找的字符包含在字符串中
>>> str = "helloworld"
>>> print(str.find('o'))
4
# 要查找的字符不包含在字符串中
>>> str = "helloworld"
>>> print(str.find('g'))
-1
  1. replace(old, new):把字符串中的str1换成str2。
>>> str = "helloworld"
>>> print(str.replace('o', '%'))
hell%w%rld
  1. split(str=""):以str为分隔符(所得结果中不含该分隔符)分割字符串。所得结果为一个列表。
>>> str = "helloworld"
>>> print(str.split("w"))
['hello', 'orld']
  1. isalnum():如果字符串至少有一个字符,并且所有字符都是字母或数字则返回True,否则返回False。
>>> str = "helloworld123"
>>> print(str.isalnum())
True
  1. isalpha():如果字符串至少有一个字符,并且所有字符都是字母则返回True,否则返回False。
>>> str = "helloworld123"
>>> print(str.isalpha())
False
  1. isdigit(): 如果字符串只包含数字(注意字符串为空的情况)则返回True,否则返回False。
>>> str = "helloworld123"
>>> print(str.isdigit())
False
  1. islower():如果字符串至少有一个区分大小写的字符,并且所有字符都是小写则返回True,否则返回False。
>>> str = "helloworld123"
>>> print(str.islower())
True
  1. isupper():如果字符串至少有一个区分大小写的字符,并且所有字符都是大写则返回True,否则返回False。
>>> str = "helloworlD123"
>>> print(str.isupper())
False
  1. isspace():如果字符串中只包含空格,则返回True,否则返回False。
>>> str = "helloworlD123"
>>> print(str.isspace())
False
>>> str = "     "
>>> print(str.isspace())
True
  1. lower():将字符串中的所有的大写转换为小写。
>>> str = "HELLOworld123"
>>> print(str.lower())
helloworld123
  1. upper():将字符串中的所有的小写转换为大写。
>>> str = "HELLOworld123"
>>> print(str.upper())
HELLOWORLD123
  1. max(str):返回字符串str中最大的字符。比较的是ASCII值。
>>> str = "HELLOworld123"
>>> print(max(str))
w
  1. min(str):返回字符串str中最小的字符。比较的是ASCII值。
>>> str = "HELLOworld123"
>>> print(min(str))
1
  1. startwith(str, beg=0, end=len(string)):检查字符串是否是以str开头,如果是则返回True,否则返回False。
>>> str = "HELLOworld123"
>>> print(str.startswith("HEL"))
True
  1. endwith(str, beg=0, end=len(string)):检查字符串是否是以str结尾,如果是则返回True,否则返回False。
>>> str = "HELLOworld123"
>>> print(str.endswith("HEL"))
False
>>> print(str.endswith("123"))
True

四、元组

4.1 创建元组

  1. 通过小括号()创建元组
  • 元组一旦定义就无法修改。
  • 元组中的数据可以是任意的数据类型。
>>> t1 = (22, 44, "abc", [1, 2], (1, [2, 88], "张三"))
>>> print(type(t1))
<class 'tuple'>
  • 元组中如果只有一个值,那么需要后面加一个逗号,否则不是元组。
>>> t2 = ("张三")
>>> t3 = (4)
>>> print(t2)
张三
>>> print(type(t2))
<class 'str'>
>>> print(t3)
4
>>> print(type(t3))
<class 'int'>
t2 = ("张三", )
t3 = (4, )
print(t2)
print(t3)
print(type(t2))
print(type(t3))

在这里插入图片描述
2. 通过tuple()创建空元组

>>> t1 = tuple()
>>> print(t1)
()
>>> print(type(t1))
<class 'tuple'>

4.2 元组赋值

同时给多个变量赋值

>>> t1, t2 = ("张三", "李四")
>>> print(f"t1的值是{t1},t2的值是{t2}")
t1的值是张三,t2的值是李四

4.3 元组相关内置函数使用

  1. len(tuple):计算元组中元素个数
>>> t1 = ("张三", ("李四", 1), [1, 3, 4])
>>> print(len(t1))
3
  1. max(tuple):返回元组中元素最大值(比较的是ASCII值)
>>> t2= ("a", "B", "d", "f")
>>> print(max(t2))
f
  1. min(tuple):返回元组中元素最小值(比较的是ASCII值)
>>> t2= ("a", "B", "d", "f")
>>> print(min(t2))
B
  1. tuple(seq):将其他数据类型转换为元组
>>> lis = [1, 2, 9, 88]
>>> print(tuple(lis))
(1, 2, 9, 88)

>>> str = "123"
>>> print(tuple(str))
('1', '2', '3')

五、集合

  • 集合(set)与字典相同均存储 key,但也只存储 key,不存储value。因 key 不可重复,所以 set 的中的值不可重复,也是无序的。
  • 集合的元素必须是可以hash类型的,也就是必须是hashable。因此集合中的元素可以是元组,但是不能是列表、字典和集合。
>>> s1 = {11, 33, "22", "张三", (1, 3), 11}
>>> print(s1)
{33, '张三', 11, '22', (1, 3)}
>>> print(type(s1))
<class 'set'>
  • 集合中的元素

5.1 创建集合

  • 集合使用花括号 {} 或者 set() 函数创建
  • 如果创建空集合只能使用 set() 函数
# 使用{}创建集合
>>> s1 = {1, 2, (1, 3), 'a'}
>>> print(s1)
{1, 2, (1, 3), 'a'}
>>> print(type(s1))
<class 'set'>

# 使用set()创建集合
>>> s2 = set("qsf")
>>> print(s2)
{'q', 's', 'f'}
>>> print(type(s2))
<class 'set'>

>>> s3 = set(['a', 'b', 'c'])
>>> print(s3)
{'b', 'c', 'a'}
>>> print(type(s3))
<class 'set'>

# 使用set()创建空集合
>>> s4 = set()
>>> print(s4)
set()

5.2 集合的常见操作

  1. 集合的并集:t | s
  2. 集合的交集:t & s
  3. 集合的差集:t - s
  4. 集合的对称差集:t ^ s
t = {1, 2, 3, 4, 5}
s = {4, 5, 6, 7, 8}

# t和s的并集:属于集合t或者属于集合s
a = t | s
print(f"t和s的并集:{a}")

# t和s的交集:同时属于集合t和s
b = t & s
print(f"t和s的交集:{b}")

# t和s的差集:属于集合t且不属于集合s
c = t - s
print(f"t和s的差集:{c}")

# t和s的对称差集:属于集合t或者属于集合s,但不会同时出现在集合t和s中
d = t ^ s
print(f"t和s的对称差集:{d}")

在这里插入图片描述

5.3 集合相关内置函数使用

  1. 集合中添加一项:s.add():直接改变原集合的内容
  2. 集合中添加多项:s.update(list):直接改变原集合的内容
  3. 集合中删除特定项:s.remove():直接改变原集合的内容
  4. 统计集合中元素的个数:len(set)
s = {1, 2, 3, 4, 5}

# 集合中添加一项:直接改变原集合的内容
s.add('helloworld')
print(f"集合中添加一项,原集合变为:{s}")

# 集合中添加多项:直接改变原集合的内容:将要添加的元素放入列表,
list1 = ["张三", "lisi", 9]
s.update(list1)
print(f'集合中添加多项,原集合变为:{s}')
# 集合中删除一项
s.remove("helloworld")
print(f'集合中删除“helloworld”,原集合变为{s}')

# 统计集合中元素的个数
print(f'统计集合s的元素个数{len(s)}')

在这里插入图片描述

六、字典

6.1 创建字典

  • 字典可以使用花括号{}和dict()函数创建
  • 创建空字典既能使用花括号{},也能使用dict()函数创建
  • 字典的key值不可重复,否则只保留第一个;value值可以重复
  • 值可以取任何数据类型,但键必须是不可变的(集合的元素就对应字典的key),如字符串,数字或元组。
# 使用花括号创建字典
d1 = {'name': '张三', 'age': '18'}
print(f'字典d1内容是:{d1}')
print(f'd1的类型是:{type(d1)}')

# 使用dict()函数创建字典
d2 = dict({'name': '张三', 'age': '18'})
print(f'字典d2内容是:{d2}')
print(f'd2的类型是:{type(d2)}')

# 使用花括号{}创建空字典
d3 = {}
print(f'字典d3内容是:{d3}')

# 使用dict()函数创建空字典
d4 = dict()
print(f'字典d4内容是:{d4}')

在这里插入图片描述

6.2 字典常用操作

  1. 访问字典里的value值:dict[key]
  2. 修改字典的value值:dict[key] = new value
  3. 向字典添加新的键值对:dict[new key] = new value
  4. 删除字典中的元素:del dict[key]
  5. 清空字典:dict.clear()
  6. 删除字典:del dict
# 使用花括号创建字典
d1 = {'name': '张三', 'age': '18'}

# 访问字典里的value值
print(f'访问字典“name”所对应的value:{d1["name"]}')

# 修改字典的value值
d1['name'] = '李四'
print(f'修改字典中“name”所对应的value,原字典变为{d1}')

# 向字典添加新的键值对
d1['address'] = "北京"
print(f'向字典添加新的键值对,原字典变为{d1}')

# 删除字典中的元素
del d1['address']
print(f'删除字典中的某键值对,原字典变为{d1}')

# 清空字典
d1.clear()
print(f'清空后的字典为:{d1}')

# 删除字典
del d1

在这里插入图片描述

6.3 字典常用方法

  1. 返回一个字典的复制:new dict = dict.copy()
  2. 创建一个新字典,以序列seq中的元素作为字典的key,所对应的value都为初始值None:new dict = dict.fromkeys()
  3. 返回指定健的值(即返回指定key对应的value);如果指定键不在字典中时,则返回默认值None;如果不想返回None,可以指定返回参数值:element = dict.get(key)
  4. 与get()方法类似,返回指定健的值(即返回指定key对应的value):element = dict.setdefault(key);如果要查找的key不存在,则会将该key添加进字典,且其对应的value为None
  5. 返回字典的所有key值,并以列表的形式保存,但返回的数据类型为dict_keys,并不是list,因此无法直接将返回结果使用列表的操作方法,如果需要使用列表的操作方法,需要进行list()强转:key_list = dict.keys()
  6. 将字典dict2的所有键值对添加到字典dict1:dict1.update(dict2)
# 使用花括号创建字典
d1 = {'name': '张三', 'age': '18'}

# 返回一个字典的复制:new dict = dict.copy()
d2 = d1.copy()
print(f'复制后的新字典为:{d2}')

# 创建一个新字典,以序列seq中的元素作为字典的key,所对应的value都为初始值None:new dict = dict.fromkeys()
d3 = d1.fromkeys('hello')
print(f'新创建的字典为:{d3}')

# 返回指定健的值(即返回指定key对应的value):element = dict.get(key)
element1 = d1.get('name')
print(f'返回字典”name“键对应的value:{element1}')
# 如果指定键不在字典中时,则返回默认值None;如果不想返回None,可以指定返回参数值
print(f'返回字典中不存在的键值:{d1.get("sex")}')
print(f'返回字典中不存在的键值:{d1.get("sex", "-1")}')

# 与get()方法类似,返回指定健的值(即返回指定key对应的value):element = dict.setdefault(key)
element2 = d1.setdefault('age')
print(f'返回指定键age对应的value:{element2}')
# 如果要查找的key不存在,则会将该key添加进字典,且其对应的value为None
element3 = d1.setdefault('sex')
print(f'返回指定键sex对应的value:{element3}')
# 查看此时d1的内容
print(f'此时的d1内容变为:{d1}')

# 返回字典的所有key值,并以列表的形式保存,但返回的数据类型为dict_keys,并不是list,因此无法直接将返回结果使用列表的操作方法,如果需要使用列表的操作方法,需要进行list()强转:key_list = dict.keys()
key_list = d1.keys()
print(f'返回字典的所有key值,并以列表的形式保存:{key_list}')
print(f'返回key的数据类型为{type(key_list)}')

# 将字典dict2的所有键值对添加到字典dict1:dict1.update(dict2)
d4 = {'sex': '女', 'address': '北京'}
d4.update(d1)
print(f'更新后的字典为:{d4}')

在这里插入图片描述

七、 控制结构

7.1 顺序结构

  • 代码从上往下依次执行

7.2 选择结构(分支结构)

  • 单分支
    语法:
if 条件:
    执行的代码
  • 双分支
if 条件:
    执行的代码
else:
    执行的代码
  • 多分支
if 条件1:
    执行的代码
elif 条件2:
    执行的代码
else:
    执行的代码
  • 嵌套分支
if 条件1:
    执行的代码
    if 条件2:
        执行的代码
    else:
        执行的代码
else:
    执行的代码

7.3 循环结构

  1. for循环
    语法:
  • for循环后可跟可迭代数据:列表、元组、字典,此时循环次数是由元素的个数决定的
  • for循环后可跟range函数
for 变量名 in 可迭代的数据:
    执行的代码
  • for循环后跟列表/元组
print('********************模块执行开始********************')
names = ['张三', '朱武', '王二', '李四']
# for循环后跟列表(元组类似)
for i in names:
    print(i)
    print('###############################################')
print('********************模块执行结束********************')

在这里插入图片描述

  • for循环后跟字典
print('********************模块执行开始********************')
info = {"name": "xiaoli", "sex": "女", "address": "北京"}
# for循环后跟字典,遍历的是字典的key,可以根据字典的key遍历字典的value
for i in info:
    print(f'字典中的key分别是:{i}')
    print('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
    print(f'字典中的value分别是:{info[i]}')
    print('###############################################')
print('********************模块执行结束********************')

在这里插入图片描述

  • for循环后跟range()函数:
    • range()函数左闭右开
    • range()函数可以产生任意范围内的正整数
# for循环后跟range()函数
# range()函数是一个左闭右开区间
# range()函数可以取任意区间内的正整数
# 只能取1-9 9个数字,且step设置为2(可选参数,可以不加)
for i in range(1, 10, 2):
    print(f'本次取出的数字是{i}')

在这里插入图片描述
2. while循环
语法:

while 条件:
    循环体中代码
  • 案例:
    • 遍历输出列表、元组、字符串
    • 求和
names = ['张三', '朱武', '王二', '李四']
# 定义一个变量,作为下标使用
idx = 0

# 判断条件:下标不能超过列表的长度
while idx < len(names):
    print(f'本次输出的值是:{names[idx]}')
    # 每循环一次,给下标+1
    idx += 1

在这里插入图片描述

# 定义一个变量,保存每次的和
s = 0

# 定义一个变量,模拟1-100这100个数
i = 1

while i <101:
    s += i
    # 每次循环,让i+1
    i += 1
print(f'1-100相加的结果是:{s}')

在这里插入图片描述

7.4 案例:综合应用

    1. 找出下列给出的字符串中,年龄大于等于30岁和小于30岁的人名,并分别保存在列表中
ageTable = '''
    诸葛亮, 28
    刘备, 48
    刘琦, 25
    赵云, 32
    张飞, 43
    关羽, 45
'''

# 定义两个空列表,分别存放年龄大于等于30岁和小于30岁的人名
l_age = []
s_age = []

# 首先对字符串进行切片操作,一行一行的处理,切片后得到一个列表
name_age_list = ageTable.split('\n')
# print(name_age_list)    # 打印切片后的结果看看长啥样

# 遍历列表,取出每一个name和age
for name_age in name_age_list:
    # 只对有值的数据进行操作,空数据跳过不处理
    if name_age == '':
        continue
    else:
        # 去除每一项中的空格
        new_nameage = name_age.replace(" ", "")
        # 将“name,age”字符串按“,”切片,得到一个列表
        name, age = new_nameage.split(",")
        if int(age) >= 30:
            l_age.append(name)
        else:
            s_age.append(name)

print('年龄超过30岁的人有:', l_age)
print('年龄不到30岁的人有:', s_age)
    1. 找出str1中存在,str2中不存在的人名
      在这里插入图片描述
# 【案例】:找出str1中存在,str2中不存在的人名
 
'''

str2 = '''

"JamesPotter",
"SeverusSnape  ",

" RubeusHagrid",

"GinnyWeasley  ",

"LuciusMalfoy"

'''

# 首先对两个字符串进行处理
# 对str1以“\n”进行切片操作,得到一个列表
str1_list = str1.split("\n")
# print(str1_list)   # 打印切片后的列表,看看长啥样

# 定义一个新的列表new_str1_list[],用于存放str1中所有的非空数据
new_str1_list = []
# 遍历列表
for s1 in str1_list:
    # 去除取出的字符串中的所有空格
    new_s1 = s1.replace(" ", "")
    # 将列表中所有非空字符串保存到new_str1_list[]
    if new_s1 == "":
        continue
    else:
        new_str1_list.append(new_s1)

# 对str2以“\n”进行切片操作,得到一个列表
str2_list = str2.split("\n")

# 定义一个新的列表new_str2_list[],用于存放str2中所有的非空数据
new_str2_list = []
# 遍历列表
for s2 in str2_list:
    # 去除取出的字符串中的所有空格
    new_s2 = s2.replace(" ", "")
    # 将列表中所有非空字符串保存到new_str2_list[]
    if new_s2 == "":
        continue
    else:
        new_str2_list.append(new_s2)

# 打印处理后的两个列表
# print(new_str1_list)
# print(new_str2_list)

# 找出str1中存在,str2中不存在的人名
# 方式一:使用集合的差来求解
# names = set(new_str1_list) - set(new_str2_list)
# print("str1中存在,str2中不存在的人名有:", names)

# 定义一个新集合,用于存放str1中存在,str2中不存在的人名
# 之所以定义集合而不是列表,是为了保证得到的结果中,名字不会重复出现
names = set()
# 方式二:使用循环遍历
for name in new_str1_list:
    if name in new_str2_list:
        continue
    else:
        names.add(name)
print("str1中存在,str2中不存在的人名有:", names)

在这里插入图片描述

八、 函数

8.1 函数的定义

  • 语法:
def 函数名():
	函数体(实现函数功能的代码)

8.2 函数的参数

1. 必填参数:
—— 在函数调用时必须传值,且个数要跟定义的形参个数相等

def add(a, b):
    s = a + b
    print(f'a+b的值为:{s}')

# 调用函数
add(1, 2)

在这里插入图片描述
2. 默认值参数:
—— 在函数定义时,指定某个形参的值,因此在函数调用时,不给该指定形参的位置传入值时就使用默认值,否则按新传入的值计算;
—— 默认值参数必须在必填参数的后面

def add(a, b, c=5):
    s = a+b+c
    print(f'a+b+c的和为:{s}')

# 调用函数
# 调用函数时不给默认参数传参
add(2, 7)
# 调用函数时给默认参数另外传参
add(2, 7, 7)

在这里插入图片描述
3. 可变参数
—— 可变参数(不定长参数):为了解决传入的参数个数不确定的情况,采用可变参数,可以接受任意个数的参数
—— 定义的顺序:必填参数、默认值参数、可变参数、关键字可变参数
—— 可变参数的定义:在形参名字前面加要给星号“”
—— 可变参数将传入的多个值,组合成了一个元组,这个现象叫做“组包”
—— 在实现的函数体中,给 该可变参数的形参名前带
,即可将组包后的元组拆开,这个现象称之为“解包”
—— 如果不给可变参数传入值,则是一个空元组

def add(a, b, *args):
    s = a + b
    print(f'相加的结果是:{s}')
    print(f'传入的可变参数是:{args}')
    # 解包
    print(*args)
# 调用函数
add(2, 3, 4, "zhang")

在这里插入图片描述

4. 关键字可变参数
—— 关键字可变参数
—— 定义的顺序:必填参数、默认值参数、可变参数、关键字可变参数
—— 关键字可变参数定义:形参名前面加**
—— 如果关键字可变参数,传入的值是一个键值对(且变量名不加引号,比如:name = “张三”),此时将键值对组合成了一个字典
如果关键字可变参数,传入的值是一个字典,则需要在传值时,字典名字前加**

def add(a, b, *args, **kwargs):
    s = a + b
    print(f'a+b的和为:{s}')
    print(f'可变参数的值是:{args}')
    # 传入的关键值参数,组合成了一个字典
    print(f'关键字可变参数的值是:{kwargs}')

# 调用函数
# 关键值可变参数传入键值对
add(1, 2, "zhangsan", 88, age=18, name="Jerry")

# 关键值可变参数直接传入字典
d1 = {"name": "小叮当", "age": 8}
add(1, 2, "Tom", 99, **d1)

在这里插入图片描述

8.3 函数的返回值

  1. 直接打印函数名,可以得到该函数在内存中的存储地址
def add(a, b):
    s = a+b
    print(f'a+b的值为:{s}')
# 直接打印函数名,可以返回该函数在内存中的位置
print(add)

在这里插入图片描述
2. 无返回值时

def add(a, b):
    s = a+b
    print(f'a+b的值为:{s}')
    
# 用r来接收函数的返回值,无返回值时显示 None
r = add(1, 2)
print(r)

在这里插入图片描述
3. 有返回值时

(1) 函数的返回值是函数体中代码执行完成的结果
(2) 使用return关键字来指定返回值
(3) Python中的返回值可以是任意类型的数据
(4) python中可以同时拥有多个返回值,各个返回值之间用逗号隔开,返回的多个值组成了一个元组
# 函数的返回值是函数体中代码执行完成的结果
# 使用return关键字来指定返回值
# Python中的返回值可以是任意类型的数据
# python中可以同时拥有多个返回值,各个返回值之间用逗号隔开,返回的多个值组成了一个元组
def add(a, b):
    s = a+b
    # python中可以同时拥有多个返回值,各个返回值之间用逗号隔开,返回的多个值组成了一个元组
    return s, "顺带返回的字符串", ["列表", 33]

# 用r来接收函数的返回值,无返回值时显示 None
r = add(1, 2)
print(f'有返回值时,输出结果是:{r}')

在这里插入图片描述

十、模块和包

10.1 模块和包的创建

  1. Python文件中讲一个.py文件称为一个模块文件。
  2. 模块文件可以放在包中(Python Package)
  3. 可以在包中继续创建子包
  4. 一般建议:同一个模块文件中的代码不超过500行;因为如果同一个模块文件中代码太多,会有可能导致变量和函数名重复的情况;而且会导致代码的阅读性很差。

10.2 在不同的模块文件中式使用其他模块封装好的函数或变量

方式一:导入整个模块文件

# 导入test.py 这个模块下的所有内容(函数和变量)
import test
# 使用变量
print(test.var1)
# 使用导入的函数
test.calc_s()
test.calc_s_c()

方式二:导入其他模块中的某些函数或变量

  • 导入某个函数
# 导入test模块下的calc_s函数
from test import calc_s
# 调用函数
calc_s()
  • 导入某个变量
# 导入test模块下的变量
from test import var1
# 使用变量
print(var1)
  • 导入多个函数和变量
# 导入test模块下的变量和某个函数,中间使用逗号隔开
from test import calc_s, var1, calc_s_c
# 使用变量
print(var1)
# 调用函数
calc_s()
calc_s_c()
  • 使用星号*导入某个模块的所有内容(不推荐:可能会存在跟当前模块的变量名和函数名重复)
# 导入test模块下所有变量和函数
from test import *
# 使用变量
print(var1)
# 调用函数
calc_s()
calc_s_c()
  • 起别名:如果要导入的其他模块下变量名或函数名与当前模块的重复,则需要给其中一个起别名
# 如果不同模块文件下的函数重名了,则需要给其中一个起别名
# 使用as起别名,别名仅限于当前这个模块使用,不会对原函数的名字造成影响
from test import calc_s as c
def calc_s():
    print("这是test03中函数calc_s")
calc_s()
# 通过别名调用
c()

十一、正则表达式

11.1 点·

  • 匹配除了换行符(\n、\r)之外的任何单个字符
  • 【举个栗子:】
    找出字符串中所有的颜色
# 找出下列字符串中所有的颜色

# re模块是python的内置模块,提供了对正则表达式的支持
import re

content = """苹果是绿色的
橙子是橙色的
香蕉是黄色的
乌鸦是黑色的"""

# 正则表达式
r = re.compile(r".色")
# 在content里面使用正则表达式查找内容,将找到的内容赋值给变量msg
msg = r.findall(content)
print(msg)

在这里插入图片描述

11.2 星号*

  • *表示匹配前面的子表达式任意次,包括0次。
  • 【举个栗子:】
    找出下列字符串中所有水果或动物的名字
# 找出下列字符串中所有水果或动物的名字

# re模块是python的内置模块,提供了对正则表达式的支持
import re

content = """苹果,是绿色的
橙子,是橙色的
香蕉,是黄色的
乌鸦,是黑色的
猴子,"""

# 正则表达式,r防止转义
r = re.compile(r".*,")
# 在content里面使用正则表达式查找内容,将找到的内容赋值给变量msg
msg = r.findall(content)
print(msg)

在这里插入图片描述

11.3 加号+

  • +表示匹配前面的子表达式一次或多次,不包括0次。
# 找出下列字符串中,后面的所有内容

# re模块是python的内置模块,提供了对正则表达式的支持
import re

content = """苹果,是绿色的
橙子,是橙色的
香蕉,是黄色的
乌鸦,是黑色的
猴子,"""

# 正则表达式,r防止转义
# +表示匹配前面的子表达式一次或多次,`不包括0次`。
r = re.compile(r",.+")
# 在content里面使用正则表达式查找内容,将找到的内容赋值给变量msg
msg = r.findall(content)
print(msg)

在这里插入图片描述

11.4 问号?

  • ?表示匹配前面的子表达式0次或1次
# 找出下列字符串中","后面的颜色

# re模块是python的内置模块,提供了对正则表达式的支持
import re

content = """苹果,绿色的
橙子,橙色的
香蕉,黄色的
乌鸦,黑色的
猴子,,"""

# 正则表达式,r防止转义
# `?`表示匹配前面的子表达式0次或1次
r = re.compile(r",.?")
# 在content里面使用正则表达式查找内容,将找到的内容赋值给变量msg
msg = r.findall(content)
print(msg)

在这里插入图片描述

11.5 花括号{}

  • {}表示匹配前面的子表达式指定的次数
# 匹配连续两个”油“或连续三个”油“

# re模块是python的内置模块,提供了对正则表达式的支持
import re

content = """红彤彤,绿油油,黑乎乎乎乎,绿油油油油"""

# 正则表达式,r防止转义
# `{}`表示匹配前面的子表达式指定的次数
# 匹配连续两个”油“或连续三个”油“
r = re.compile(r"油{2,3}")
# 在content里面使用正则表达式查找内容,将找到的内容赋值给变量msg
msg = r.findall(content)
print(msg)

在这里插入图片描述

11.6 方括号[]

  • 方括号表示要匹配 指定的几个字符之一
content = """sadfsafastrhtgyfujh"""
# re模块是python的内置模块,提供了对于正则表达式的支持
import re
# 正则表达式
# 匹配所有的”s“和”a“
p = re.compile("[sa]")
# 在content里面使用正则表达式查找内容,将找到的内容赋值给变量
message = p.findall(content)
print(message)

在这里插入图片描述

11.7 贪婪模式和非贪婪模式

我们要把下面的字符串中的所有html标签都提取出来,

source = '<html><head><title>Title</title>'

得到这样的一个列表

['<html>', '<head>', '<title>', '</title>']

<.*>这样写是不对的,因为在python中 .* 都是贪婪的,会尽可能多的向后匹配,

为了解决这问题就要使用非贪婪模式 ,只需要加?即可

content = """<html><head><title>Title</title>"""
# re模块是python的内置模块,提供了对于正则表达式的支持
import re
# 正则表达式
p = re.compile("<.*?>")
# 在content里面使用正则表达式查找内容,将找到的内容赋值给变量
message = p.findall(content)
print(message)

11.8 竖线|

  • |表示匹配前者或后者
content = """001-苹果价格-60
002-橙子价格-70
003-香蕉价格-80"""
# re模块是python的内置模块,提供了对于正则表达式的支持
import re
# 正则表达式
# 匹配所有的”-,格,0“
p = re.compile("-|格|0")
# 在content里面使用正则表达式查找内容,将找到的内容赋值给变量
message = p.findall(content)
print(message)

在这里插入图片描述

11.9 括号()组选择

  • ()称之为正则表达式的组选择,是从正则表达式匹配的内容里面抠取出起张总的某些部分
# 以(姓名,手机号)的格式显示
content = """张三,手机号码15945678901
李四,手机号码13945677701
王二,手机号码13845666901"""
# re模块是python的内置模块,提供了对于正则表达式的支持
import re
# 正则表达式
p = re.compile("(.\D),\D*(\d*)")
# 在content里面使用正则表达式查找内容,将找到的内容赋值给变量
message = p.findall(content)
print(message)

在这里插入图片描述

11.10 对元字符的转义

反斜杠 \ 在正则表达式中有多种用途。
所谓元字符的转义,就是让元字符失去原来的含义

content = """苹果.是绿色的
橙子.是橙色的
香蕉.是黄色的"""
# re模块是python的内置模块,提供了对于正则表达式的支持
import re
# 正则表达式
p = re.compile(".*\.")
# 在content里面使用正则表达式查找内容,将找到的内容赋值给变量
message = p.findall(content)
print(message)
  • \d 匹配0-9之间任意一个数字字符,等价于表达式 0-9

  • \D 匹配任意一个不是0-9之间的数字字符(字母、下划线),等价于表达式 ^0-9

  • \s 匹配任意一个空白字符,包括 空格、tab、换行符等,等价于表达式 \t\n\r\f\v

  • \S 匹配任意一个非空白字符,等价于表达式 ^ \t\n\r\f\v

  • \w 匹配任意一个文字字符,包括大小写字母、数字、下划线,等价于表达式 a-zA-Z0-9_;缺省情况也包括 Unicode文字字符,如果指定 ASCII 码标记,则只包括ASCII字母

  • \W 匹配任意一个非文字字符,等价于表达式 ^a-zA-Z0-9_

11.11 起始、结尾位置和单行、多行模式

^ 表示匹配文本的 开头 位置。

正则表达式可以设定 单行模式 和 多行模式

如果是 单行模式 ,表示匹配 整个文本 的开头位置。

如果是 多行模式 ,表示匹配 文本每行 的开头位置。

python中默认是单行模式

content = """001-苹果价格-60,
002-橙子价格-70,
003-香蕉价格-80,"""
# re模块是python的内置模块,提供了对于正则表达式的支持
import re
# 正则表达式
# 默认是单行模式,如果要找每一行开头的内容,则需要开启多行模式re.MULTILINE或者re.M
p = re.compile("^\d+-", re.MULTILINE)
# 在content里面使用正则表达式查找内容,将找到的内容赋值给变量
message = p.findall(content)
print(message)

在这里插入图片描述

$ 表示匹配文本的 结尾 位置。

如果是 单行模式 ,表示匹配 整个文本 的结尾位置。

如果是 多行模式 ,表示匹配 文本每行 的结尾位置。

content = """001-苹果价格-60
002-橙子价格-70
003-香蕉价格-80"""
# re模块是python的内置模块,提供了对于正则表达式的支持
import re
# 正则表达式
# 默认是单行模式,如果要找每一行开头的内容,则需要开启多行模式re.MULTILINE或者re.M
p = re.compile("-\d*$", re.MULTILINE)
# 在content里面使用正则表达式查找内容,将找到的内容赋值给变量
message = p.findall(content)
print(message)

在这里插入图片描述

十二、文件读写

12.1 文本文件读写(.txt)

  1. 语法:
# 方式一:

# 打开文件
f = open("读写文件的位置", "文件打开方式"):
读取 或 写入的代码
# 关闭文件
f.close()
# 方式二:

# 打开文件
with open("读写文件的位置", "文件打开方式") as f:
    读取 或 写入的代码
  1. 常用打开模式
  • r:只能读
  • r+:可读可写,文件不存在不会创建;文件指针位置是0,写入的时候,要注意文件指针位置,不然会覆盖原内容
  • w:只能写,文件不存在会自动创建;开始时文件指针位置是0,写会清除原文件所有内容
  • w+:可读可写,文件不存在会自动创建;开始时文件指针位置是0,读和写都会清除源文件所有内容
  • a:只能写,文件不存在会自动创建;开始时文件指针位置在末尾。
  • a+:可读可写,文件不存在会自动创建;开始时文件指针位置是末尾,如果需要读取内容,则需要将文件指针移动到文件的开始位置。
    3. 案例一:读取文件内容,查看文件指针位置
# r模式的使用:如果不指定打开模式,则默认就是只读模式r
# 打开一个已存在的文件
f = open("demo04.txt")
# 读取文件内容
'''
read():如果不指定读取的字符个数,则表示读取文本文件中的所有内容,读取的内容是一个字符串
read(2):从文件指针为0的位置读取2个字符
'''
# 从开头读取两个字符,用info接收
# 获取此时文件指针的位置
print(f"开始时候文件指针的位置是:{f.tell()}")
info = f.read(2)
print(f'从开头读取两个字符:{info}')
# 获取此时文件指针的位置
print(f"读取两个字符后文件指针的位置是:{f.tell()}")
# 关闭文件
f.close()

demo04.txt 文件的内容是:

jddkagdjagjid
sdjagkdak
kdjgdjgn

代码输出结果是:
在这里插入图片描述
4. 案例二:移动文件指针,读取文件内容

f = open("demo04.txt", "r")
# 获取文件指针
print(f"开始时文件只指针的位置是:{f.tell()}")
print(f'显示移动后文件指针的位置:{f.seek(6)}')
info = f.read(2)
print(f'移动文件指针后,开始读取两个字符:{info}')
# 关闭文件
f.close()

demo04.txt 文件的内容是:

jddkagdjagjid
sdjagkdak
kdjgdjgn

代码输出结果是:
在这里插入图片描述
5. 案例三:readlines()和readline()

  • readlines()读取文件中全部内容,将结果放在一个列表中,且将每一行的换行符也会读取进去。
  • readline()
    readlines()用法:
f = open("demo04.txt")
print(f"readlines()读取文件中全部内容:{f.readlines()}")
# 关闭文件
f.close()

在这里插入图片描述
readline()用法:

f = open("demo04.txt")
# 读取完整一行,不读取行末换行符
print(f.readline())
# 获取文件指针
print(f"文件指针的位置是:{f.tell()}")
# 从文件指针后读取两个字符
print(f"从文件指针后读取两个字符:{f.read(2)}")
print(f"读取后的文件指针位置是:{f.tell()}")
# 关闭文件
f.close()

demo04.txt 文件的内容是:

jddkagdjagjid
sdjagkdak
kdjgdjgn

代码输出结果是:
在这里插入图片描述
6. 案例四:r+模式

  • 可读可写,文件不存在时不会创建文件;
  • 刚打开文件时,文件指针的位置是0,写入的时候要注意文件指针,注意不要覆盖文件内容。
"""
不读取,直接写入文件,从文件的起始位置开始写,并覆盖源文件内容
"""
f = open('demo04.txt', 'r+')
# 获取文件指针
print(f'开始时文件指针的位置是:{f.tell()}')
# 写入内容:从文件指针位置开始写入内容,对原内容覆盖
f.write('HELLOWORLD')

"""
先读取文件,然后进行写入操作,此时从文件末尾位置开始写入
"""
# 获取文件指针
print(f'写入内容后文件指针的位置是:{f.tell()}')
print(f"读取两个字符:{f.read(2)}")
# 获取文件指针
print(f'读取两个字符后文件指针的位置是:{f.tell()}')
# 写入内容:从文件末尾位置开始写入内容
f.write('8888')
# 关闭文件
f.close()

代码输出结果是:
在这里插入图片描述
demo04.txt 文件的写入前内容是:

jdiagjgjdiagjidfjgi
lksamgdkoekotfjrigj
jsahnfejfpgjszjdig
djasigjierjagijri

demo04.txt 文件的写入后内容是:

HELLOWORLDagjidfjgi
lksamgdkoekotfjrigj
jsahnfejfpgjszjdig
djasigjierjagijri8888

7. 案例五:w模式

  • 只能写不能读,会覆盖原文件全部内容
  • 如果写入的文件不存在,则会创建文件
f = open('demo04.txt', 'w')
f.write("hello")
# 关闭文件
f.close()

demo04.txt 文件的内容是:

HELLOWORLDagjidfjgi
lksamgdkoekotfjrigj
jsahnfejfpgjszjdig
djasigjierjagijri8888

demo04.txt文件写入后内容是:

hello

8. 案例六:w+模式

  • 可读可写(读和写都会清除原文件的所有内容),文件不存在则会创建
f = open("demo04.txt", "w+")
# 写入内容
f.write("helloworld")
# 获取文件指针
print(f"获取文件指针:{f.tell()}")
# 移动文件指针
f.seek(0)
# 读取文件内容
print(f.read())
# 关闭文件
f.close()

demo04.txt文件写入前内容是:

djaignidajgkdakgo
sjaigjijgiajijidga

demo04.txt文件写入后内容是:

helloworld

代码输出结果:
在这里插入图片描述
9. 案例七:a模式

  • 只能写,末尾追加,文件不存在则会创建;
  • 文件指针在文件的末尾
f = open("demo04.txt", "a")
f.write("hello")
# 关闭文件
f.close()

demo04.txt文件写入前内容是:

djaiggnahsnagj
djaigjidaggdgadhello

demo04.txt文件写入后内容是:

hello

10. 案例八:a+模式

  • 可读可写,文件指针在文件的末尾,会采用追加的方式添加内容到末尾;如果需要读取内容,则需要将文件指针移动到文件的开始位置。
f = open("demo04.txt", "a+")
f.seek(0)
# 读取内容
print(f.read())
# 写入内容
f.write("python")
# 关闭文件
f.close()

demo04.txt文件写入前内容是:

djaigndkasgkg
dajigjdmasigj

demo04.txt文件写入后内容是:

djaigndkasgkg
dajigjdmasigjpython

代码输出结果:
在这里插入图片描述

12.2 Excel文件的读写(.xls .xlsx)

1.为什么要对Excel文件进行读写呢?

  • 因为自动化测试数据可以放在Excel文件中进行管理,要通过代码将测试数据读取出来。
  • 可以利用第三方库openpyxl来处理:既可以读取,也可以写入,但是只能处理新版的.xlsx这种格式,老的.xls格式无法处理。

2. 安装openpyxl库

pip install openpyxl

12.2.1 使用openpyxl创建Excel表格

获取默认sheet

  • ws = wb.active

修改当前sheet名字

  • ws.title = "sheet_name"

保存文件

  • wb.save("Excel文件名字.xlsx")
# 从openpyxl库中导入Workbook包,注意首字母大写
from openpyxl import Workbook

# 创建一个Excel对象
wb = Workbook()
# 获取Excel中默认(下标为0的sheet)的sheet对象
ws = wb.active
# 在默认的sheet中添加内容

# 方式一
# 给sheet中的B列第二行添加内容
ws["B2"] = "80"

# 方式二
# 给sheet中的第二行第一列添加内容
ws.cell(2, 1).value = "卡梅利多"

# 修改当前sheet的名字
ws.title = "成绩表"

# 保存到当前文件夹,保存文件一定要加后缀
wb.save("学生成绩表.xlsx")

12.2.2 创建Excel表格,并将字典内容写入表格

报编码错误:SyntaxError: Non-UTF-8 code starting with ‘\xb4’ in file ……

  • 首行添加# coding:utf-8
# coding:utf-8
# 如果出现编码错误,可以在首行添加 coding:utf-8
# 导包
from openpyxl import Workbook

# 卡梅拉成绩表
name_score = {
    "卡门": 88,
    "卡梅拉": 90,
    "卡梅利多": 87,
    "皮迪克": 96
}
# 创建表格对象
wb = Workbook()
# 获取默认sheet
ws = wb.active
# 修改sheet的名字
ws.title = "卡梅拉一家"
# 设置表头
ws["A1"] = "名字"
ws["B1"] = "成绩"

# 定义一个变量i,用来记录行号
i = 2
# 使用items()可以将字典转换为一个可迭代的对象,每次循环取出一个键值对,并分别赋值给name,score
for name, score in name_score.items():
    ws.cell(i, 1).value = name
    ws.cell(i, 2).value = score

    # 每次循环过后要将行号的值+1
    i += 1
# 保存表格
wb.save("卡梅拉的一家成绩单.xlsx")

代码运行结果:
在这里插入图片描述

12.2.3 创建Excel表格,并将列表或元组内容写入表格

# 从openpyxl库中导入Workbook包,注意首字母大写
from openpyxl import Workbook

name_scores = [
    ('段天涯',10),
    ('上官海棠',9),
    ('归海一刀' ,9),
    ('成是非', 2),
    ('古三通', 50),
    ('朱无视', 52),
    ('曹正淳',43),
    ('万三千', 23)
]
# 创建表格对象
wb = Workbook()
# 获取默认sheet
ws = wb.active

# 修改sheet标题
ws.title = "天下第一积分赛"

# 设置表头
ws['A1'] = '姓名'
ws['B1'] = '积分'
# 定义一个变量,用来表示行号
i = 2

# 遍历列表
for line in name_scores:
    name = line[0]
    score = line[1]
    # 将列表中的内容填入表格
    ws.cell(i, 1).value = name
    ws.cell(i, 2).value = score

    # 每循环一次,将行号的值+1
    i += 1

# 保存文件
wb.save('天下第一张积分表.xlsx')

在这里插入图片描述

12.2.4 创建sheet

创建sheet

  • wb.create_sheet("sheet_name", index)

获取表格中所有的sheet名字

  • wb.sheetnames
# 导入包
from openpyxl import Workbook

# 创建一个Excel对象
wb = Workbook()
# 创建sheet
wb.create_sheet("第一", 0)
wb.create_sheet("第二", 1)
wb.create_sheet("第三", 2)

# 获取表格中所有的sheet名字
print(f"表格中所有的sheet名字是:{wb.sheetnames}")
# 选择名字是“第二”的sheet,并填入内容
ws = wb["第二"]
ws["A1"] = "你好呀!"
# 保存
wb.save("创建sheet.xlsx")

代码运行结果:
在这里插入图片描述
在这里插入图片描述

12.2.5 在指定表格中 插入行、插入列

选中已存在Excel文件

  • wb = load_workbook("Excel文件名称.xlsx")

插入/删除行/列:需要导入包

  • from openpyxl import load_workbook

插入行/列

  • 插入行:ws.insert_rows(插入起始行号,插入行数(不写默认插入一行))
  • 插入列:ws.insert_cols(插入起始列号,插入列数(不写默认插入一列))

删除行/列

  • 删除行:ws.delete_rows(插入起始行号,删除行数(不写默认删除一行))
  • 删除列:ws.delete_cols(插入起始列号,删除列数(不写默认删除一列))

原文件内容:
在这里插入图片描述

# 导入包
from openpyxl import load_workbook

# 指定Excel
wb = load_workbook("卡梅拉的一家成绩单.xlsx")
# 指定sheet
ws = wb["卡梅拉一家"]

# 插入行:在第三行插入两个空行(如果插入一行,第二个参数可以省略不写)
ws.insert_rows(3, 2)
# 插入列:在第二列插入两个空列(如果插入一列,第二个参数可以省略不写)
ws.insert_cols(2, 2)

# 保存:如果文件名字与打开文件的时候保持一致,则是在原文件修改;如果不一致则是另存为
wb.save("卡梅拉的一家成绩单.xlsx")

代码执行结果:
在这里插入图片描述

12.2.6 在指定表格中 删除行、删除列

# 导入包
from openpyxl import load_workbook

# 指定Excel
wb = load_workbook("卡梅拉的一家成绩单.xlsx")
# 指定sheet
ws = wb["卡梅拉一家"]

# 删除行
ws.delete_rows(3, 2)
# 删除列
ws.delete_cols(2, 2)
# 保存:如果文件名字与打开文件的时候保持一致,则是在原文件修改;如果不一致则是另存为
wb.save("卡梅拉的一家成绩单.xlsx")

原文件内容:
在这里插入图片描述
代码执行结果:
在这里插入图片描述

12.2.7 获取最大行数、列数(注意调用的方法后没有括号)

  • 获取最大行数:ws.max_row
  • 获取最大列数:ws.max_column
# 导入包
from openpyxl import load_workbook

# 指定Excel
wb = load_workbook("卡梅拉的一家成绩单.xlsx")
# 指定sheet
ws = wb["卡梅拉一家"]
# 获取最大行数
rows = ws.max_row
print(f'最大行数是:{rows}')
# 获取最大列数
cols = ws.max_column
print(f'最大列数是:{cols}')
# 保存:如果文件名字与打开文件的时候保持一致,则是在原文件修改;如果不一致则是另存为
wb.save("卡梅拉的一家成绩单.xlsx")

在这里插入图片描述

【案例】

将表格中数据取出来,并以列表的形式存储:
在这里插入图片描述
存储格式为:
[[“卡门”, “88”], [“卡梅拉”, “90”], [“卡梅利多”, “87”], [“皮迪克”, “96”]]

# 存储格式为:[["卡门", "88"], ["卡梅拉", "90"], ["卡梅利多", "87"], ["皮迪克", "96"]]
# 导包
from openpyxl import load_workbook

# 指定要操作的Excel
wb = load_workbook("卡梅拉的一家成绩单.xlsx")

# 指定要操作的sheet
ws = wb["卡梅拉一家"]

# 获取最大行
rows = ws.max_row
# 获取最大列
cols = ws.max_column

# 保存处理过程的内容
# 定义一个列表,用来存放取出来的所有数据
name_scores = []

# 根据行号和列号,获取Excel文件的内容
for r in range(2, rows+1):
    # 定义一个列表,用来存放每一行的数据
    row_list = []
    for c in range(1, cols+1):
        # 测试每行的输出内容
        # print(ws.cell(r, c).value)
        row_list.append(ws.cell(r, c).value)

    name_scores.append(row_list)
print(f'打印取出内容的格式:{name_scores}')

代码执行结果:
在这里插入图片描述

从 0 开始学 Python 自动化测试开发(二):环境搭建 关于环境搭建,其实笔者一直在犹豫是否要写,因为环境搭建本身是既简单而又可能很复杂的事情。简单是指如果一切顺利,一个命令(Linux 下)或者一路点 “Next/下一步” 就能搞定;复杂是指一旦遇到点问题,可能解决起来就比较麻烦,因为涉及到操作系统环境变量的一些设置,还有每个人的系统环境配置的差异,这些个性化差异网上未必有现成的答案可供搜索参考,初学者如果不知道原理的话,很难排除。考虑到这个专栏受众是从 0 到 1 学习编程和自动化测试,为照顾到小白同学,那我们还是尽量不跳过任何一点,让大家能从零基础学会。 阅读详情

相关推荐

测试开发超级高频的基础知识面试题!记住至少能帮助你度过99%的理论难关

【测试开发高频面试题精要】腾讯8年测试专家总结金融领域核心知识点: 测试基础 测试生命周期:需求分析→测试报告全流程 设计方法:等价类划分/边界值分析 主流工具:Selenium/Appium工作原理 Python核心 数据结构:列表/字典高级操作 特色功能:装饰器/生成器应用 测试扩展:日志装饰器/覆盖率分析等……

bingbingida的博客 951

Python 测试开发从入门到高手成长之路

Python 测试开发从入门到高手成长之路

2201_75735270的博客 731

python测试开发课程_小蜗分享:Python测试开发全套学习路线

该楼层疑似违规已被系统折叠隐藏此楼查看此楼第一阶段:专业基础课程阶段目标:1. 熟练掌握IT核心技术:编程,数据库,操作系统,版本控制2. 能够熟练运用所学技术搭建各类服务器环境3. 深入理解软件研发过程各种疑难杂症及处理手段4. 掌握Python编程技术并熟练运用Python进行程序设计知识点:1、Web页面元素,布局,CSS样式,盒模型,JavaScript程序设计,函数,基础算法,正则表达...

weixin_28848739的博客 894

软件测试进阶篇----Python

软件测试需要掌握的Python语言基础,以及单元测试框架unittest,超全一手笔记!!

小王同学的博客 1585

2026四款AI原生IDE实测:Trae、Qoder、CodeBuddy、Cursor能力边界深度解析

AI原生IDE正从代码编辑器演进为开发者智能工作流中枢,其核心在于对上下文理解、AST编辑意图建模与多模态任务调度的工程化实现。区别于传统插件式AI辅助,真正的AI原生IDE需具备知识库嵌入、符号图索引、操作链固化等底层能力,从而支撑Figma转码、N+1查询修复、跨语言迁移等复杂场景。Trae强调中文语境与企业规范的强绑定,Qoder聚焦AST级编辑轨迹预测,CodeBuddy通过IDE/插件/CLI三态划分控制权边界,Cursor则以云端Agent实现开发任务的时空并行。本文基于真实项目压测,揭示免费版

ctk87443的博客 2462

SAP MM 物料描述MAKTX 40个字符不够用的问题处理

SAP物料描述表,长度40个字符一般情况下,40个字符在描述中也够用了,但是要加上规格之类的额外描述就不一定了,特别是对于辅助件-刀具。解决方案一:对maktx增强,换成CHAR80或者CHAR100的,但是风险较大,涉及到好多地方,另外SAP+ 算号器 也不支持。解决方案二:增强字段。内部顾问,建议在 那就在这里加一个字段,具体过程如下:1、创建域2、创建架构3、附加架构4、GUI 设置 5、后台设置6、MASS/MM17字段新增。过程1、创建域 SE112、创建结构 se11 3、MARA附加架构

GAVIN 4729

Python虚拟环境——测试工程师Python开发实战

Python之所以强大,除了其本身的特性强大,更重要的是Python拥有非常多的第三方工具。强大的软件库,让开发人员将精力集中在业务上,从而避免重复“造轮子”的浪费。但众多的软件库形成了复杂的依赖关系,加上Python 2和Python 3两个大版本的兼容性问题,这些对管理项目依赖造成了不少困扰。

软件自动化测试技术交流、资源分享 358

2 海康视觉平台VisionMaster 上手系列:大纲及准备

海康视觉平台VisionMaster 大纲,课前准备 快速入门 工业机器视觉 机器视觉

HuangGong2022的博客 1万+

Python|测试开发篇——基础

语法:字符串.find(sub_str,start,end)返回值:①sub_str中第一个字符在大字符串中的下标 ②如果没有找到,返回-1语法:字符串.replace(old_str,new_str,count)返回值:替换之后的完整的字符串语法:字符串.split(sep,maxsplit)sep:字符串按照sep拆分,默认是空白字符(空格,换行\n,tab键\t)maxsplit:分割次数,默认不写就是全部分割语法:字符串.join(列表) 括号中的内容也可以是其他容器。

qq_52907748的博客 1193

『言善信』Fiddler工具 — 1、Fiddler介绍与安装

文章目录1、Fiddler简介2、Fiddler功能3、Fiddler工作原理4、Fiddler安装 1、Fiddler简介 Fiddler是强大的抓包工具之一,它能记录所有客户端和服务器之间的HTTP和HTTPS请求,是web调试的利器。 Fiddler是位于客户端和服务端之间的HTTP代理,它的原理是以web代理服务器的形式进行工作的,使用的代理地址是:127.0.0.1,端口默认为8888,我们也可以通过设置进行修改。 Fiddler可以抓取支持HTTP代理的任意程序的数据包,如果要抓取https会

繁华似锦Fighting 1468

C51红外接收与发射控制及原理编码与解码

基于38khz的NEC协议红外发射简易电路图NEC协议产生红外光数据编码 0 1结合程序红外接收接收电路解码过程解码代码 红外发射 通过通过红外二极管发射红外光,三极管的状态来控制。 红外模块一般都是三个引脚,vcc,gnd,dat,通过控制dat口的来控制发射红外光。 简易电路图 将数据口连接到单片机的引脚为上,控制io口的电平状态,来控制三极管的导通状态,从而发射红外光。 NEC协议 NEC协议特点:8位地址和8位命令为提高可靠性,地址和命令都传输2次,脉冲间隔调制38kHz载波频率。 包含引导码,

yangfeng20的博客 1万+

Python测试开发进阶路线,零基础入门到精通,收藏这篇就够了

它可以在设备或模拟器上运行Python脚本,模拟用户操作,比如点击、滑动、输入等,从而进行自动化测试。**工具实战:**集中训练抓包工具(Wireshark)、渗透测试工具(Nmap)、漏洞扫描工具(Nessus 基础版)的使用,结合模拟场景练习工具应用(掌握基础扫描逻辑,为 SRC 漏扫工具进阶做准备)。实战技能训练:开展漏洞扫描、漏洞利用、电商系统渗透测试、内网渗透、权限提升(Windows、Linux)、代码审计等实战训练,结合运维中熟悉的系统环境设计测试场景(强化红蓝对抗攻击端技术能力)。

Python_0011的博客 764

【Unity 反向运动学插件】Final IK 一套完整的IK解决方案

Final IK是Unity中一套完整的反向运动学解决方案,提供多种IK算法(CCD、FABRIK等)和功能模块,包括全身IK、VR驱动、武器瞄准、视线跟随等。其核心是通过数学方法计算关节旋转,使末端骨骼精确到达目标位置。系统支持多约束求解、旋转限制、动画烘焙及交互系统,采用模块化设计,兼顾性能与扩展性,适用于动作游戏、VR等需要高质量角色控制的场景,是Unity生态中最成熟的IK工具链之一。

2403_88403568的博客 1004

测试开发基础

(1)JAVA知识   Q1:List、Set、Map 之间的区别   List 是一个有序并且允许元素重复的集合,它的底层数据结构是数组,数组的优缺点都很明显,就是查询速度很快,但是要做数据移动,比如增加、删除速度就会很慢。   Set 是一个无序且不允许元素重复的集合,它的底层数据结构是哈希表,它的优缺点是跟数组完全相反的,既查询速度慢,但是增加、删速度很快。   Map也是集合的一部分,它最...

qq_39075632的博客 381

破盾实录|Vueling航空阿卡迈防护逆向:从503挑战到Cookie生成的全流程拆解

摘要:文章分享了作者在爬取西班牙伏林航空(Vueling)机票数据时,遭遇阿卡迈(Akamai)防护系统的实战经历。起初简单的请求被拦截返回503错误,分析发现阿卡迈通过混淆JS代码实施"挑战-验证"机制,需模拟真实浏览器环境才能获取有效Cookie。作者详细拆解了逆向过程:从抓包分析JS挑战流程,到破解代码混淆和控制流平坦化,最终用Python+Pyppeteer成功模拟浏览器特征,突破防护获取数据。整个过程涉及JS反混淆、环境检测绕过和Cookie生成验证等关键技术点,为类似防护系统

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1643

灵境视界:基于云计算与深度学习的智能手语识别AR眼镜

灵境视界”不仅仅是一款AR眼镜,它代表了未来无障碍沟通设备的发展方向。随着云计算与深度学习技术的不断进步,未来我们将进一步优化识别算法,提升翻译精度,并扩展更多语言和手语类型,为全球听障人士提供更加全面的沟通解决方案。是一款融合了云计算与深度学习技术的增强现实(AR)眼镜,专为听障人士和手语使用者设计。这款眼镜不仅具备先进的AR显示功能,还能实时识别并翻译手语,打破听障人士与健听人士之间的沟通障碍,推动无障碍社会的建设。,让沟通无界,视界无限。

qq_62634009的博客 725

金九银十软件测试面试题(800道)

为此我特意整理出一份(超详细笔记/面试题)它几乎涵盖了所有的测试开发技术栈,非常珍贵,人手一份肝完进大厂妥妥的!(含测试理论,需求分析,测试模型,测试计划,测试策略,测试类型,测试流程,用例设计,缺陷报告,测试案例....)(Linux的常用命令,Linux练习题,大厂高频Linux面试题...)​十、LordRunner篇(2022版)​八、selenium篇(2022版)四、web测试篇(2022版)五、API测试篇(2022版)​六、管理工具篇(2022版)九、性能测试篇(2022版)...

软件测试前沿技术分享 336

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

和橘子菇凉一起开始python之旅吧!

和橘子菇凉一起开始python之旅吧!学习目标&职业规划一.python基础学习二.接口自动化三. selenium网页自动化,以前QTP四.appium手机端的自动化五.自动化项目实战六.职业规划1.自动化测试工程师/性能测试工程师/安全测试工程师2.测试开发3.管理路线4.讲师,内训师 学习目标&职业规划 备注:每日自学内容总结 一.python基础学习 课前准备:python3.6以上,官网下载pycharm(它是一个ide,即集成开发环境) 学习内容如下: 字符串,列表与元组 布尔

橘子菇凉的博客 145

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

2023金九银十软件测试面试题(800道)

今年你的目标是拿下大厂offer?还是多少万年薪?其实这些都离不开日积月累的过程。为此我特意整理出一份(超详细笔记/面试题)它几乎涵盖了所有的测试开发技术栈,非常珍贵,人手一份 肝完进大厂 妥妥的!由于细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!一、基础篇:(2023版)(含:测试理论,需求分析,测试模型,测试计划,测试策略,测试类型,测试流程,用例设计,缺陷报告,测试案例…)

2301_76643199的博客 196

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

测试开发学习路线

一篇文章了解测试开发

iboyang的博客 2万+

测试开发学习路线(非常详细)零基础入门到精通,收藏这篇就够了

大家好,我是洋子,一名测试开发工程师在测试行业,我们一般都听说过这3种岗位:测试工程师(功能测试),自动化测试工程师,测试开发工程师。目前在互联网大厂,基本都只招测试开发工程师,意味着做软件测试也需要具备代码能力对于测试开发这种近几年才在国内火起来的岗位,在市场上基本没有可供参考的学习路线,很多非计算机科班的同学想转行做软件测试拿高薪,却不知道怎么学习于是我花了快一个月的时间,整理出了测试开发的学习路线,供大家学习参考。

leah126的博客 4818

【测试】测试开发学习路线,助你通关大厂

前言 大家好,我是洋子,一名测试开发工程师 在测试行业,我们一般都听说过这3种岗位:测试工程师(功能测试),自动化测试工程师,测试开发工程师。目前在互联网大厂,基本都只招测试开发工程师,意味着做软件测试也需要具备代码能力 对于测试开发这种近几年才在国内火起来的岗位,在市场上基本没有可供参考的学习路线,很多非计算机科班的同学想转行做软件测试拿高薪,却不知道怎么学习 于是我花了快一个月的时间,整理出了测试开发的学习路线,供大家学习参考。本学习路线是结合我自己在百度做测试开发基础上整理出来的,详细列举出测试开发需

欢迎关注【微信公众号】测试开发Guide,从功能测试进阶测试开发 2万+

Python语言的测试开发

在软件开发的过程中,测试是确保软件质量的重要环节。随着敏捷开发和持续集成(CI/CD)理念的普及,测试开发的重要性愈发凸显。在众多编程语言中,Python因其简单易懂的语法、丰富的库支持和强大的社区资源,成为了测试开发领域的热门选择。本文将探讨Python语言在测试开发中的应用、工具、最佳实践和未来发展趋势。

2501_90356446的博客 554
上一篇: 软件测试之测试用例设计方法总结
下一篇: 【Python测试开发】Python高级
Lucifer__hell
博客等级 码龄8年 53粉丝 54原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值